InnoDB的RR隔离级别能否防止“幻读”
一、快照读和当前读(参考这篇文章)
在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,不是数据库最新的数据。这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库最新版本数据的方式,叫当前读 (current read),这两者是冲突的。
1.快照读
当执行select操作时,Innodb默认执行快照读,会记录下这次select后的结果,之后select 的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了(InnoDB默认隔离级别是可重复读,和这个说法一致)。快照的生成时机是在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,读到的数据中就会有B添加的那条数据。之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。
先提一句:快照读是通过MVCC和undo log实现的,暂不展开
2.当前读
对于会修改数据的操作(update、insert、delete)都是采用当前读的模式。在执行这几个操作时会读取最新的记录,即使是别的事务提交的数据也可以查询到。假设要update一条记录,但是在另一个事务中已经delete掉这条数据并且commit了,如果update就会产生冲突,所以在update的时候需要知道最新的数据(例子可参考这篇文章的“试验一”)
那么如何使用select操作实现当前读呢?答案是需要手动加锁(例子可参考这篇文章的“试验四”)
select * from table where ? lock in share mode;
select * from table where ? for update;
二、select for update 和 select lock in share mode
select…lock in share在select的结果集上加一个共享锁.允许其他会话读取这些数据,但不允许修改.
select…for update 将读取的结果集加一个排他锁. 阻止其他会话读或写该结果集.
而这里加的锁是next-key lock
三、当前读时如何避免幻读
当前读是通过next-key lock实现,next-key lock会锁住一个范围,并且锁定记录本身,使得其他事务不能操作锁定范围内的记录,也就杜绝了出现“幻影”。(因为其他事务根本无法在此范围里插入数据)
四、快照读时如何避免幻读
呵呵,快照读时没有避免幻读,只是在select时都是读到历史数据,看起来是没有幻读,但是当你更新时,发现,明明没有这条数据呀?!(例子可参考中的“试验一”和“试验二”)
五、结论
在InnoDB的RR隔离级别下
1.对于快照读,通过MVCC实现了重复读,但是没有完全避免幻读,只是在简单select时避免了幻读
2.要完全避免幻读,需要手动加锁进行当前读,这时会使用next-key lock避免幻读
上一篇: C++ 创建文件夹
推荐阅读
-
MySQL数据库的隔离级别之可重复读为什么能够有效防止幻读现象的出现
-
数据库的隔离级别以及脏读,不可重复读和幻读
-
Mysql事务以及四中隔离级别实例2以及InnoDB如何解决当时读的幻读问题
-
事务的隔离级别和幻读问题
-
数据库基础知识ACID,隔离级别RC,RR,RU,SERIALIZABLE,Phantom Rows幻读,解决幻读,脏读dirty read
-
【数据库】MySQL Innodb在RR(可重复读)级别如何避免幻读
-
【大话Mysql面试】-InnoDB可重复读隔离级别下如何避免幻读?MVCC和next-key是什么
-
spring事务的隔离级别。如何避免脏读或者幻读
-
InnoDB的RR隔离级别能否防止“幻读”
-
MySQL 的 Innodb 在 REPEATABLE-READ 的事务隔离级别下,幻读问题记录