MySQL中MVCC的实现原理
MySQL中的MVCC(多版本并发控制)是一种通过维护数据历史版本实现高并发读写的技术,其核心实现原理可分为以下五个部分:
一、隐藏字段与版本链
隐藏字段
InnoDB为每行数据添加三个隐藏字段: •
DB_TRX_ID
(6字节):记录最后一次修改该行的事务ID(包括INSERT/UPDATE/DELETE)。•
DB_ROLL_PTR
(7字节):指向Undo Log中该行历史版本的指针,用于构建版本链。•
DB_ROW_ID
(6字节,可选):当表无显式主键时自动生成的隐藏主键,用于聚簇索引。Undo Log版本链
• 每次事务修改数据时,旧版本数据会被写入Undo Log,并通过
DB_ROLL_PTR
形成版本链。例如,事务A(ID=100)插入数据,事务B(ID=200)更新后,版本链结构为:当前数据 → 事务B版本 → 事务A版本
。• 版本链允许事务回溯历史数据,解决读写冲突时的数据一致性问题。
二、Read View机制
事务执行快照读(如普通SELECT)时生成一致性视图(Read View),包含以下核心属性:
m_ids
:当前活跃事务ID列表。min_trx_id
:活跃事务中的最小ID。max_trx_id
:下一个将分配的事务ID(即当前最大事务ID+1)。creator_trx_id
:创建该Read View的事务ID。
三、数据可见性判断规则
通过对比数据行的DB_TRX_ID
与Read View属性,确定是否可见:
规则1:若
DB_TRX_ID < min_trx_id
,说明该版本在Read View创建前已提交,可见。规则2:若
DB_TRX_ID ≥ max_trx_id
,说明该版本由未来事务生成,不可见。规则3:若
min_trx_id ≤ DB_TRX_ID < max_trx_id
: • 未提交事务:DB_TRX_ID
在m_ids
中,不可见。• 已提交事务:
DB_TRX_ID
不在m_ids
中,可见。规则4:若
DB_TRX_ID == creator_trx_id
,说明是当前事务自身修改的数据,直接可见。
若当前版本不可见,则通过DB_ROLL_PTR
回溯Undo Log版本链,直至找到符合条件的历史版本。
四、隔离级别的影响
读已提交(RC)
• 每次快照读生成新的Read View,能读到其他事务已提交的最新数据。
• 示例:事务A第一次读取数据后,事务B提交更新,事务A第二次读取会生成新视图并看到新数据。
可重复读(RR)
• 事务首次快照读生成Read View,后续操作复用该视图,保证整个事务期间数据一致性。
• 示例:事务A第一次读取数据后,事务B修改并提交,事务A第二次读取仍看到旧数据。
五、MVCC的优缺点
优点 | 缺点 |
---|---|
读写不阻塞(非锁定读) | 存储开销大(多版本维护) |
减少锁竞争与死锁风险 | 无法完全解决幻读(当前读仍可能触发) |
支持高并发场景 | 依赖后台Purge线程清理旧版本 |
示例分析
假设事务ID=301的事务查询数据行,当前版本由事务ID=300修改(未提交),版本链包含事务ID=200(已提交)和事务ID=100(已提交)的版本:
- Read View的
m_ids
包含活跃事务ID=200、300、301,min_trx_id=200
,max_trx_id=302
。 - 事务301会跳过事务300的版本(未提交),选择事务100的版本(
DB_TRX_ID=100 < min_trx_id
),返回旧数据。
通过上述机制,MySQL在保证事务隔离性的同时,实现了高性能的并发读写。具体实现细节在不同版本中可能优化调整,但核心原理保持一致。