多版本并发控制(MVCC)
MVCC 的思路是这样:我们为每一个事务都分配连续递增的ID(XID),同时每次更新一行数据的时候,为这一行生成一个新版本,并在新版本上记录执行这次修改事务的XID。同时全局维护一个当前未提交的事务 XID 列表(后续简称 xid_set)。
当我们要读数据的时候,首先记录当前最大的事务ID是多少(后续简称 next_xid),比这个值更大的事务在我们读数据时都还没开始执行,所以当读到数据版本XID比 next_xid 大的时候,说明当前版本在本次查询中不应该被读到,需要找这一行数据更早的版本了。但并不是 XID 比 next_xid 小的版本就一定都可以被读到,因为可能之前的一些事务还没有提交。所以在开始读数据时,除了记录 next_xid,还需要记录此时全局未提交的事务 XID 列表(就是复制一份这一时刻的 xid_set)。当读到的版本 XID 小于 next_xid 且不在 xid_set 中,这个数据就是当前应该被读取到的版本了。
所以读操作应当看见哪些版本,受这两个值的影响:
- 开始读操作时的最大的事务ID next_xid
- 开始读操作时未提交的事务ID列表 xid_set
这两个值唯一确定了一份数据快照(ReadView),限制了当前读事务一定只能读到已提交的数据版本,无法读到执行到一半还未提交的事务产生的变更。当写事务提交时,只需将自己的XID从全局未提交的事务列表中删除,即可让只有的读操作看到自己的变更。MVCC就是用这种方式来实现原子性的,这种方式实现原子性几乎不需要锁。
MVCC的具体实现有以下两种:
- 直接保存数据的所有历史版本
- 记录数据的最新值和undo log,通过 undo log 来恢复数据的历史版本
在 MySQL 中使用的是第二种。
来源:oschina
链接:https://my.oschina.net/u/3231771/blog/4807335