MySQL-MVCC

MySQL-MVCC

MySQL通过ReadView和undo log实现了MVCC

ReadView

创建该ReadView的事务id(creator_trx_id) 创建该ReadView时,当前活跃且未提交事务id列表(m_ids) 创建该ReadView时,最小活跃未提交事务id(min_trx_id) 创建该ReadView时,下一个事务id(max_trx_id)

记录的隐藏列(只存在聚簇索引,非聚簇索引内不存在隐藏列):

创建该记录的事务id(trx_id) roll_pointer指向前一个版本记录
  1. trx_id < min_trx_id,说明创建该ReadView时,修改该版本记录的事务已提交,则该版本记录对事务creator_trx_id可见
  2. trx_id >= max_trx_id,说明这个版本记录的事务是在ReadView创建后才启动的,则该版本记录对事务creator_trx_id不可见
  3. 否则:min_trx_id < trx_id < max_trx_id,若:
    • trx_id in m_ids,说明在该ReadView创建时,修改这个版本记录的事务尚未提交,则不可见
    • trx_id not in m_ids,说明在该ReadView创建时,修改这个版本记录的事务已提交,则可见
    • 例:启动1 2 3 4四个事务,3执行非常快,已结束了;若此时启动事务5,则此时ReadView中m_ids为1 2 4,事务3的改动对事务5可见

事务隔离级别

  • 可重复读Repeatable Read:启动事务时创建一个ReadView,整个事务期间都用这个ReadView
  • 读提交Read Comitted:每次读数据时都会生成一个新的ReadView

通过MVCC,RR很大程度上避免了幻读,但不能完全避免:事务2插入一条新记录并提交,然后事务1虽然读不到这条新纪录,但是能够修改这条数据,修改完再读就能读到了。这是因为修改后,这条记录的trx_id变成事务1,对于事务1的ReadView而言是可见的。

所以要彻底解决幻读还是需要使用锁。


MySQL-MVCC
http://example.com/2026/01/21/MySQL-MVCC/
作者
Kon4tsu
发布于
2026年1月21日
许可协议