为什么可重复读隔离级别可以很大程度上解决幻读问题?
- 对于快照读(即普通的select语句),通过MVCC和ReadView的作用,事务启动时生成的ReadView会在整个事务执行期间复用,所以自然不会出现幻读
- 对于当前读(select… for update),通过记录锁+间歇锁的方式,使得B事务不能在A事务两次查询期间进行插入操作,从而避免了幻读的问题
可重复读隔离级别还可能出现的幻读问题
第一种情况
当A事务开启事务后进行查询id为xxx比如5的记录,发现不存在这条记录,但是另一个B事务开启然后插入了一条id为5的记录并提交。由于update、delete、insert语句每次执行之前都会查询最新的记录,所以除了select…for update,它们也是当前读。这样,A事务更新id为5的记录后,由于事务自己更新的记录自己总是可见,因此当A事务再次查询时会发现这次能够查到id为5的记录了。
第二种情况
事务A开启后执行一条快照读查询id为5的记录发现不存在,然后另一个事务B开启然后插入一条id为5的记录并提交,接着A事务通过当前读再次查询发现可以查到id为5的记录。
- 解决方法:事务开启后马上执行select…for update语句给记录加锁