该实验基于 CentOS 7 + MySQL 5.7 进行
打开两个窗口连接到MySQL
第一个连接的事务我们命名为 T1
第二个连接的事务我们命名为 T2
T2 发生在 T1 的 O1 操作结束以后。
可以看到在 RR 隔离级别下,T1 的 O1 操作先进行查询 id=1 的用户信息,显示没有结果,按照正确的逻辑,此时我们是可以插入 id=1 的用户的;
然后我们在 T2 中执行了插入操作,插入了 id=1 的用户,并且提交成功;
然后我们在 T1 中也执行形同的插入操作,试图插入 id=1 的用户,此时报错,说违反了主键约束;
然后我们在 T1 中再次查询 id=1 的用户信息,发现仍然是没有结果。
这对于事务 T1 来说,是不是很过分?我先查询,你告诉我没有,我插入,你不让我插入,说主键冲突,我再查询,还是没有,你要怎样???
通过这个实验,可以清楚的看到,MySQL 的 RR 隔离级别通过 MVCC 确实保证了两次 select 结果的一致性,但此时 insert 带来的主键冲突问题并不能解决,我认为这应该称之为“半幻读”。
有人说通过 select ... for update 可以加锁避免幻读,是你没用而已。我认为 for update 手动加锁避免幻读并不是 RR 隔离级别本身带来的特性,并不能说 RR 隔离级别能够避免幻读。