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指向前一个版本记录 |
|---|
- 若
trx_id < min_trx_id,说明创建该ReadView时,修改该版本记录的事务已提交,则该版本记录对事务creator_trx_id可见 - 若
trx_id >= max_trx_id,说明这个版本记录的事务是在ReadView创建后才启动的,则该版本记录对事务creator_trx_id不可见 - 否则:
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/