假设读者已经知道了InnoDB的几个事务隔离级别,本笔记仅仅针对于在repeatable read级别下的可重复读与幻读现象。

写本文的目的是一开始被可重复读和幻读的定义给弄迷糊了,在InnoDB开启了rr的隔离级别后,mvcc是可以保证可重复读的,即在两个事务内,多次select同一个条件的语句返回的结果集都是相同的,即使有第三个事务更新了某一行。

那么不就是不存在幻读这个现象了么?一开始我也是这样认为的,认为幻读就是保证可重复读就可以了。仔细搜索文章后才发现幻读的概念不是这样,比如开启了两个事务,操作只有一个f1为pk的表。在tx1中查询所有的结果集,返回empty set,那么就认为没有数据,然后在tx2中插入了一条f1=1的数据,在tx1中插入数据f1=1,结果会返回duplicated entry。

所以mvcc解决了不可重复读的问题,但是实现了这个也导致了无法读取到别的事务已经提交的数据,那么有些逻辑可能执行起来就有错了。这就是幻读的概念,幻读也就是读不到别的事务已提交的数据,然而假如开启了不可重复读的事务隔离级别,就没法实现可重复读的隔离了,这是一对相冲突的概念。

所以为了保证这种情况的发生,mysql提供了next-key lock来规避这个问题,在rr的隔离级别和next-key lock的支持下,这个问题就可以迎刃而解了。

具体用法是,还是上面tx1,tx2的场景,tx1在执行的时候,先使用

select * from t1 where f1 = 1 for update

select for update执行后,会给f1=1这一行假如一个record lock,因为这个是唯一的主键,假设是一个模糊的范围,那么gap lock就会加入,它是一个范围锁,record lock + gap lock就是next-key lock。

在for update执行后,tx2执行插入f1=1的语句后,会堵塞,因为该行已经被tx1锁住了,在tx1中插入了f1=1的数据并提交后,tx2会报错duplicated entry,假设rollback了,那么tx2会执行成功。

参考文章:

innodb-record-level-locks
innodb-next-key-locking
isolevel_repeatable-read
innodb-consistent-read

共 0 条回复
暂时没有人回复哦,赶紧抢沙发
发表新回复

作者

sryan
today is a good day