定义
MySQL的MVVC(Multi-Version Concurrency Control,多版本并发控制)是一种用于实现数据库的并发访问和事务隔离级别的技术,特别适用于InnoDB存储引擎。
MVVC的核心思想
是在不使用传统锁或尽量减少锁使用的情况下,通过维护数据的不同版本来提供对同一数据项的并发访问,同时保证事务的隔离性。以下是MVVC机制的主要原理和组件:
1. 版本链与行格式
版本链:在InnoDB中,每个数据行都有可能对应多个版本(历史版本)。这些版本按照时间顺序链接在一起形成一个版本链。每当事务对数据行进行修改时,都会创建一个新的版本,并将其加入到版本链中。新版本成为当前版本,旧版本继续保留在链中,直至不再被任何活跃事务需要。
行格式:InnoDB中的数据行除了包含实际数据外,还附加了一些额外信息以支持MVCC。这些信息通常包括:
-
事务ID(Transaction ID, trx_id):记录创建或修改该行的事务ID。对于插入或更新操作,trx_id表示创建该版本的事务;对于删除操作,trx_id记录的是删除该行的事务。
-
回滚指针(Roll Pointer, roll_ptr):指向该行在回滚段(Undo Log)中的undo记录。通过回滚指针可以获取到该行的前一个版本或恢复到之前的某个状态。
-
可见性标识(如删除标记、创建/删除时间戳等):用于判断该行版本对某个事务是否可见。
2. 事务视图与快照读
事务视图:每个事务在启动时都会获得一个唯一的事务ID,并根据其隔离级别构建一个视图(read view)。事务视图记录了当前事务能看到哪些版本的数据:
-
最小事务ID(min_trx_id):小于这个ID的事务在当前事务启动前已经提交,其修改对当前事务可见。
-
最大事务ID(max_trx_id):大于这个ID的事务在当前事务启动后才开始,其修改对当前事务不可见。
-
未提交事务列表(trx_ids):处于活跃状态且在当前事务启动时尚未提交的事务ID列表。这些事务的修改对当前事务不可见。
快照读:在MVCC下,普通的SELECT查询(非锁定读,如SELECT ... FROM ... WHERE ...)被称为“快照读”,它们读取的是事务视图创建时的数据版本。快照读不会阻塞其他事务的写操作,也不受其他事务未提交的写影响。
3. 可见性判断
当事务执行快照读时,对于查询到的每一行数据,MVCC依据以下规则判断该行版本是否对当前事务可见:
- 如果该行版本的trx_id小于当前事务视图的
min_trx_id
,则认为该版本在当前事务启动前已经提交,可见。 - 如果该行版本的trx_id大于当前事务视图的
max_trx_id
,则认为该版本在当前事务启动后才创建,不可见。 - 如果该行版本的trx_id在
min_trx_id
和max_trx_id
之间,且不在未提交事务列表中,可见。 - 否则,不可见。
如果当前版本不可见,MVCC会沿着版本链回溯,寻找下一个符合条件的可见版本供当前事务使用。
4. 更新与删除操作
对于更新操作,InnoDB并不直接在原数据行上修改,而是创建一个新的版本并将新版本链入版本链中。原版本的可见性由MVCC判断规则决定。
对于删除操作,实际上是对数据行打上删除标记,并创建一个删除版本。物理删除(从数据页中真正移除)会在清理阶段(purge)由后台线程异步进行,确保在事务提交后其他事务仍能看到其之前版本的行。
5. 回滚与清理
回滚:当事务需要回滚时