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避免幻读

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值