五分钟看懂MySQL幻读的原理解析(2022.11)

        说实话,从事开发工作三年,一直对幻读的原理并没有搞懂,之前也有看过一些帖子,各有各的说法,但是都“点到为止”,并没有说清楚其中的原理,我也就这样一知半解过来了,在一次看《凤凰架构》一书中,终于理解了幻读的原理,现记录下来分享给大家,若有错误,轻喷谢谢。

疑问的产生

slecte count(1) from books where price < 100 //时间顺序1 事务T1

insert into books(name,price) values ('深入理解Java虚拟机',90) //时间顺序2 事务T2

slecte count(1) from books where price < 100 //时间顺序3  事务T1

以上情况是否会产生幻读?

不会

        此种情况可以在很多帖子中看到,无非就是两个事务并发执行的情况下,会产生何种结果。不乏一些帖子会说此种情况也会产生幻读,或者说幻读产生的情况就是在事务T1执行时,事务T2进行了插入,所以T1事务在第二次快照读时产生了幻读。

        所以在此已经出现了一定的观点分歧,这让我感到疑惑,但当我看到《凤凰架构》(此后简称为《凤凰》)一文中描述该过程为:一个例子是MySQL/InnerDB的默认隔离级别为可重复读,但他在只读事务中可完全避免幻读问题,譬如上面例子中,事务T1只有查询语句,是一个只读事务,所以上述问题在MySQL中并不会出现

        读到此作者已经给出很明确的答复:是不会出现幻读的,那么有一部分帖子的结论已经存在错误了。

读到此有两个关键点:

  1. 可重复读事务隔离级别原理
  2. 为什么在只存在查询语句的情况下不会出现幻读问题

mvcc(多版本并发控制)

以上问题都指向了该作用机制。其实该机制严格遵循以下规则运行:

不妨将版本理解为数据库中每一行记录都从在两个看不见的字段:CREATE_VERSION,DELETE_VERSION

  1. 插入数据时:CREATE_VERSION记录插入数据的事务ID,DELETE_VERSION为空
  2. 删除数据时:DELETE_VERSION记录删除数据的事务ID,CREATE_VERSION为空
  3. 修改数据时:将修改数据视为“删除旧数据,插入新数据”的组合,即先将原有数据复制一份,原有数据的DELETE_VERSION记录修改数据的事务ID,CREATE_VERSION为空。复制后的新数据CREATE_VERSION记录修改数据的事务ID,DELETE_VERSION为空。

可重复读隔离级别的规则为:

        总是读取CREATE_VERSION小于或等于当前事务ID的记录,在这个前提下,如果数据仍有多个版本,则取最新的(事务ID最大)。

        那么上面的事务执行的例子可以得到解释,事务T2的事务ID肯定是大于事务T1的,对于事务T1,在可重复读的隔离级别下(从命名也能理解,就是能多次读取到相同的数据),事务T1只会读取到小于等于事务T1的数据,由于事务ID的递增,事务T1是不会读取到事务T2插入的数据的。所以在可重复读隔离级别下,不会也不可能产生能读到事务T2的新插入数据的情况,否则可重复读隔离级别的定义将被打破,唯一的例外为以下情况。

 幻读的产生

        如果大家注意到MVCC在处理修改数据的时候,那么就能够发现关键所在,先给出幻读的产生必要条件:

  1. 先:事务T2先进行了插入操作        
  2. 后:事务T1进行了范围修改操作

        请注意标红的点,必须按照以上顺序才会出现幻读的情况(不考虑当前读,只是采用快照读的情况下),事务T1在进行范围修改的情况下,由于没有间隙锁的约束,连带把事务T2的新插入数据一并修改了,并且新的数据的CREATE_VERSION记录修改数据的事务ID,也就是相当于把本来事务ID大于自身事务ID的不可见数据,刷新成为了自己可见的数据!这就产生了幻读。

        我相信只要明白了以上原理的小伙伴,对于读已提交,读未提交也能很快理解了。看到这里幻读产生的原理已经解释完毕了,无非深刻掌握事务隔离级别的定义和MVCC的作用机制就行。以下为防止幻读产生的做法也可以一起顺带学习下,是不是整个原理都融会贯通了?

间隙锁的作用

        间隙锁也可称之为范围锁(Range Lock):对于某个范围直接加排他锁,在这个范围内的数据不能被写入。详细点为:不仅不能修改该范围内已有的数据,也不能在该范围内新增或者删除任何数据,后者是一组排他锁的集合无法做到的。

        在可重复读的隔离级别下,就是没有范围锁来禁止在该范围内插入新的数据,这是一个事务受到其他事务的影响,隔离性被破坏的表现。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值