什么是事务

事务就是要保证一组数据库操作,要么全部成功,要么全部失败。也就是ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。

隔离性与隔离级别

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念(隔离级别越高,效率越低)。

SQL标准的隔离级别

1、读未提交:一个事务还没提交时,它做的变更就能被其他事务看到。

2、读提交:一个事务提交后,它做的变更才能被其他事务看到。

3、可重复读:一个事务执行过程中看到的数据,总是和 这个事务开始时看到的数据时一致的。该事务未提交的变更对其他事务也是不可见的。

4、串行化:将事务串行执行,如果出现冲突,则后执行的事务必须等前面的执行完才可以执行。

image-20230330100101877

假如数据库只有一列,且只有一个值c = 1,执行上面事务时,不同隔离级别得到的结果如下:

1、读未提交:虽然事务b没提交,但是可以被事务A看到,所以V1的值是2,提交后查询到的V2还是2提交事务后查到的V3还是2。

2、读提交:因为这种隔离级别只有提交后才能被看到,所以查询V1时,因为B没提交,所以是1,而V2和V3因为B提交了事务,所作的就该可以被看到,所以V2和V3都是2。

3、可重复读:因为可重复读会保证事务期间查询到的数据和事务开始时一致,那么在事务提交前,V1和V2的值都会是1,而V3因为事务结束,而且事务B已经提交,所以结果是2。

4、串行化:在这种隔离级别下,由于事务A先开始,所以事务B在修改时会被阻塞,直到A提交后,才可以执行。所以V1和V2的值都是1,而V3在提交事务A后才查询,此时B已经被唤醒执行并且提交,所以值是2。

隔离的实现

在可重复读的隔离级别下,事务启动时会创建一个视图,整个事务存在期间都是用这个视图。

在读提交隔离级别下,这个试图是每个SQL语句开始执行的时候创建的。

读未提交没有视图的概念,它永远返回最新值。

串行化是通过加锁避免并行访问。

可重复读的实现

每条记录更新时都会同时记录一条回滚操作,记录上的最新值都可以通过回滚操作回到前一个状态值。

假设一个值从1被按顺序改成了2,3,4,那么回滚日志就会有类似记录:

image-20230330103610703

有了上面的记录,我们实现不同隔离级别下,对同一条记录查询到不同的值。比如在A、B、C里面,值分别是1,2,4。简单来说,就是同一个值在系统中可以保存多个版本。但是并非真正的保存至,像上面的视图,如果要获取A,就只能从C开始一步一步回滚。

事务的开启方式

以下两种:

1、显式启动事务语句, begin 或 start transaction。配套的提交语句是commit,回滚语句是rollback。

2、set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit 或 rollback 语句,或者断开连接。

参考

《MySQL45讲》