1、数据库事务基础知识

1.1 数据库事务概述

1.1.1 存储引擎对事务的支持情况

在MySQL的存储引擎中,只有InnoDB是支持事务的。

1.1.2 事务的基本概念

什么是事务?
事务是一组逻辑操作单元,使数据从一种状态换到另一种状态。这组逻辑单元中的操作,要么全做,要么全不做,是一个不可分割的工作单位。
事务处理的原则:
保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当一个事务中执行多个操作时,要么所有事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所有修改,整个事务回滚(rollback)到最初状态。

1.1.3 事务的四大特性(ACID)

事务的ACID特性分别是指原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。

  • 原子性(atomicity):

原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部提交,要么全部失败回滚。

  • 一致性(consistency):

一致性是指事务执行的结果必须是使数据库从一个一致性状态,变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。
这种状态跟具体到业务有关,满足业务上的具体要求的状态就是合法的、正确的状态。
如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说不一致的状态。比如A、B两个装好,从A中取出一万元存入B,取出和存入在一个事务中,如果只做一个操作,那么业务上,这个数据就是不一致的。可见一致性和原子性是密切相关的。

  • 隔离性(isolation):

事务的隔离性是指一个事务的执行不能被其他事务干扰。也就是说,一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

  • 持久性(durability):

持久性是指一个事务一旦提交,它对数据库中数据的改变应该是永久性的,接下来的其他操作和数据库故障不应该对这个事务的执行结果有任何影响。
持久性是通过事务日志来保证的。日志包括了重做日志和回滚日志。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重合后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。

事务是恢复和并发控制的基本单位。
保证事务ACID特性是事务管理的重要任务,事务ACID特性可能遭到破坏的因素有:

  • 多个事务并行运行时,不同事务的操作交叉执行;
  • 事务在运行过程中被强行停止。

在第一种情况下,数据库管理系统必须保证多个事务的交叉运行不影响这些事务的原子性;在第二种情况下,数据库管理系统必须保证被强行中止的事务对数据库和其他事务没有任何影响。
这些就是数据库管理系统中恢复机制和并发控制机制的责任。

1.1.4 事务的状态

事务是一个抽象的概念,它其实对应着一个或者多个数据库操作。MySQL根据这些操作执行的不同阶段,把事务大致划分成几个状态:

  • 活动的(active):

事务对应的数据库操作正在执行过程中时,就说该事物处于 活动的 状态。

  • 部分提交的(partially committed)

当事务中的最后一个操作执行完成,但是由于操作都在内存中执行,所造成的影响并没有刷新到磁盘时,据说该事物处于部分提交的状态。

  • 失败的(failed):

当事务处在 活动的 或者 部分提交的 状态时,可能遇到了某些错误,比如数据库自身的错误、操作系统的错误、或者直接断电等,而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在 失败的 状态。

  • 中止的(aborted)

如果事务执行了一部分而变为 失败的 状态,那么久就需要把已经修改的事务中的操作还原到事务执行前的状态。 换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销过程称为 回滚。 当 回滚 操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事务处在了 中止的 状态。

  • 提交的(commited):

当一个处在 部分提交的 状态的事务将修改过的数据全部同步到磁盘上后,我们就可以说该事务处在了 提交的 状态。

image.png

1.2 如何使用事务

事务的完成过程:
步骤1:开启事务;
步骤2:一系列的DML操作;
步骤3:结束的状态:提交的状态、中止的状态。

1.2.1 显式事务

image.png

1.2.2 隐式事务

image.png

1.2.3 隐式提交数据的情况

image.png

image.png

1.3 事务的隔离级别

MySQL是个客户端/服务器(c/s)架构的软件,对于同一个MySQL服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称为一个会话(session)。
每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说,可能要同时处理多个事务。而事务具有隔离性,理论上某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交后,其他事务才可以继续访问这个数据。但是这样对性能影响太大,我们既想保持事务的隔离性,又想让服务器在处理访问同一数据的多个事务时性能尽量高些,那就要看二者如何权衡了。

1.3.1 数据并发问题

针对事务的隔离性和并发性,要如何做出取舍?先看一下访问相同数据的事务,在不保证串行执行(也就是执行完一个再执行另一个)的情况下,可能会出现哪些问题。

  1. 脏写(Dirty Write):

对于两个事务,事务A和事务B,如果事务A修改了还没提交的事务B修改过的数据,那就意味着发生了脏写。

  1. 脏读(Dirty Read):

两个事务,事务A和事务B,事务A读取了已经被事务B更新,但是还没有提交的字段。这就是脏读。如果之后事务B回滚,那么事务A读取到的内容就是临时且无效的。

  1. 不可重复读(Non-Repeatable Read):

对于两个事务,事务A和事务B,事务A读取了一个字段,然后事务B更新了该字段。之后事务A再次读取同一个字段,值就不同了。
或者说,不可重复读,是指在同一个事务内,多次读取同一数据,当这个事务还没有结束的时候,另一个事务也访问该数据。由于第一个事务的两次读取数据之间,第二个事务进行了数据修改,那么第一个事务的两次读取到的数据可能是不一样的。
解决办法:只有在修改事务完全提交之后,才可以读取数据。

  1. 幻读(Phantom):

对于两个事务,事务A和事务B,事务A从一个表中读取了一个字段,然后事务B在该表中插入(课上说,必须是插入才算幻读,删除不算)了一些新的行。之后如果事务A再次读取同一个表,就会多出几行,这就意味着发生了幻读。
或者说,幻读是指当事务不是独立执行时发生的一种现象。比如第一个事务对一个表中的数据进行了修改,这个修改涉及到表中的全部数据行。同时,另外一个事务向表中插入一行新的数据。那么就会发现,操作第一个事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。
例如:事务一读取所有字段A等于100的记录,假设有十条,这时事务2向表中新增了一条字段A等于100的记录,那么事务1再次读取时,会读到11条;
解决办法: 在操作事务完成数据处理之前,任何其他事务都不可以添加新数据;

—-> 不可重复读的重点在于修改/删除,同样的条件,读取过的数据,再次读取出来发现值不一样了;
幻读的重点在于新增,同样的条件,第一次和第二次读出来的记录数不一样了;

1.3.2 SQL中的四种隔离级别

1.3.1中介绍了几种并发事务执行过程中可能遇到的一些问题,这些 问题有轻重缓急之分,按照这些问题的严重性排序:
脏写 > 脏读 > 不可重复读 > 幻读
我们愿意舍弃一部分隔离性来换取一部分性能,设立一些隔离级别,隔离级别越低,并发问题发生的就越多,但是并发性能越高。
SQL标准中设立了4个隔离级别:
image.png
image.png

1.3.3 MySQL中的隔离级别

SQL中的四中隔离级别,MySQL中都支持。MySQL的默认隔离级别是REPEATABLE READ,可重复读。能够解决脏读和不可重复读,但是存在幻读的可能性。

1.3.4 如何设置事务的隔离级别

image.png

2、MySQL事务日志