MySQL 可重复读解决幻读了么?#
在 MySQL 的 InnoDB 存储引擎中,默认的事务隔离级别为 可重复读(Repeatable Read),它通过使用 Read View 来实现对幻读的解决。 尽管可重复读很大程度上解决了幻读问题,但在某些特定场景下,仍然存在幻读现象。
可重复读如何解决幻读?#
主要通过两种手段解决幻读:
- 针对普通select的快照读,使用MVCC的方式解决幻读。在可重复读的隔离级别下,事务第一次执行SELECT时会创建一个Read View,之后的SELECT都会使用这个Read View来判断数据的可见性,从而避免了幻读。
- 针对select … for update的当前读,使用Next-Key Lock,也就是记录锁➕间隙锁的方式来解决幻读。如果有其他的事务在Next-Key Lock范围内插入了一条记录,这个插入语句会被阻塞。
可重复读仍然存在幻读的场景#
虽然可重复读通过Read View和Next-Key Lock解决了大部分幻读问题,但在某些特定场景下,仍然可能出现幻读现象。例如:
场景#
场景1: 事务A执行普通的select,事务B在插入了一条数据并提交事务。但是事务A更新了事务B插入的数据,这个记录的trx_id隐藏列就变成了事务A的ID了。之后事务A再次执行select时,这条记录就变成了可见的了。
场景2: time1时刻,事务A执行普通的select,这个是快照读,没有加锁。 time2时刻,事务B在插入了一条数据并提交事务。 time3时刻,事务A执行select … for update,这时候变成了当前读,会直接读到最新的数据,会加上锁。