面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?

字节后台一面凉经放这,有需要自己去看哈 字节跳动飞书后台工程师一面,应该是个凉经

Q:你讲讲innodb的锁机制吧
A:blablablabla介绍了行锁表锁意向锁,读锁写锁
Q:还有呢
A:介绍了四种锁算法,record lock, gap lock, next-key lock, previous-key lock,最后我提了一嘴,innodb在rr隔离级别下是通过next-key算法来避免幻读问题的(先别骂,第一次面试紧张死了,确实有问题)
Q:在rr级别下能解决幻读问题那为什么不叫幻读级别呢,你做过实验吗?
A:我跟着书里做过实验,开了两个事务blablablabla

反正最后凉了就是了,感谢信也无,冷处理(安详.jpg
然后重新翻书看,然后和牛友们探讨,然后和学长询问,仍旧觉得没问题,只是觉得应该加上mvcc来描述会更好

《MySQL技术内幕 InnoDB存储引擎》
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第1张图片
MySQL8.0官方文档在这里插入图片描述

并且自己也重新做了实验
有以下数据
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第2张图片
现在我们开启两个事务A,B,事务A执行select,事务B执行insert,分快照读和当前读两种情况。

快照读

顾名思义,读的是快照,具体实现是mvcc,再详细是undo log,不做细究。
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第3张图片

当前读

当前读是通过上锁实现的,也就是innodb通过next-key算法(行锁+间隙锁)为我们将这块区域锁上了,所以事务B无法对其修改。

面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第4张图片

然后和朋友研究,最终发现,就描述上来说,next-key算法确实能避免幻读现象,这句话本身没问题,但是面试官的问题应该是rr隔离级别下怎么能避免幻读问题?

确实如书中所说,next-key能解决幻读问题,但这是手动加的,而在可序列化的隔离级别下则是默认实现的。
其次你说那mvcc的快照读呢,不也能避免吗?

起先,我确实一直是这么理解的,直到朋友给我看了这篇博客: 史上最详尽,一文讲透 MVCC 实现原理。

然后我进行了如下实验,也就是那篇博客的6.3的例子
还是原汁原味的表
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第5张图片
事务A除了select还执行update,事务B负责插入数据,于是。
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第6张图片

幻读现象发生了!

由这个例子说明,一旦事务A的修改操作覆盖到了其他事务插入的“幻行”,那么在下次select的时候,也会把这行数据一起查出来

什么是快照读?

原因在这里大概说一下,我们知道可重复读级别下mvcc读到的是当前事务开始时的数据,实质上是这样的:
首先mvcc会给行记录额外增加三个字段
• DB_TRX_ID:记录插入或更新后的最后一个事务的事务ID(事务id可以当作自增,也就是说事务id与事务开启先后顺序相关)
• DB_ROLL_PTR:指向该行对应的undo log的指针
• DB_ROW_ID:单调递增的行ID
在快照读中,每当一个事务更新一条数据时,都会在写入undo log后将这行记录的隐藏字段 DB_TRX_ID 更新为当前事务的ID,当另一个事务来select数据时,读到该行数据的 DB_TRX_ID 不为空并且与自身不同,就会进行判断,如果他指向的事务ID比当前ID小,说明对应的事物是在当前事务开始前提交的,那就可以读;如果他指向的事务ID比当前ID大,则说明这行数据是在当前事务执行过程中被其他事务所修改提交的,于是就会根据隐藏的 DB_ROLL_PTR 字段指向的undo log进行逻辑上的回溯操作拿到当前事务开启时的原数据。
拿上面的例子来说就是:
事务A快照读后,事务B启动并提交了insert操作,这个时候这条记录的事务id指向事务B,事务A再执行快照读时不会把它纳入结果,因为事务B的id大于事务A的id,根据undo log发现这条记录他本就不存在。但是如果此时事务A执行的操作覆盖到了这条insert的记录,那这条记录的事务id就会指向事务A,此时事务A再次执行快照读的时候就会发生幻读现象了。

这个问题MySQL官方文档中也提出了,引用了其他博主的翻译,没原链接
面试被反问,RR级别下能解决幻读问题那为什么不叫幻读级别?_第7张图片

最后,假如面试官再次问我 —— RR级别下能解决幻读问题那为什么不叫幻读级别?
A:平常我们学习的rr确实存在幻读问题,但是在innodb下不同,它可以解决,但是解决的并不完美。
首先我们可以通过手动加锁阻塞另一个线程的insert,也就是通过innodb的next-key算法,其次我们也可以通过mvcc实现快照读,但是mvcc存在缺陷,就是一旦某个事物在事务中的修改操作覆盖到了其他事务插入的“幻行”,那么这些“幻行”在下次查询时就会再次出现,从而出现幻象问题。

你可能感兴趣的:(数据库,mysql,数据库)