【Mysql】MySQL的MVCC及实现原理,核心目标与全流程图解
MySQL的MVCC及实现原理,核心目标与全流程图解
- 一、MVCC核心
- 解决两大问题:
- MVCC 全流程图解
- 二、MVCC核心实现组件
- 1. 隐藏字段(InnoDB表必有)
- 2. Undo Log(版本链)
- 3. ReadView(可见性判断核心)
- 三、可见性判断算法(RR隔离示例)
- 代码级判断逻辑:
- 四、不同隔离级别的实现差异
- 五、实战案例演示(RC vs RR)
- 结果对比:
- 六、关键参数优化
- 七、MVCC的限制
一、MVCC核心
MySQL MVCC(多版本并发控制)是 InnoDB 引擎实现高并发的核心技术,其本质是 通过数据多版本实现读写操作的并行执行。
解决两大问题:
- 读写冲突:读操作不阻塞写操作
- 事务隔离:实现RC(读已提交)、RR(可重复读)隔离级别
📌 关键设计:通过数据多版本+版本可见性判断实现
MVCC 全流程图解
二、MVCC核心实现组件
1. 隐藏字段(InnoDB表必有)
字段名 | 长度 | 作用 |
---|---|---|
DB_TRX_ID | 6字节 | 最新修改该行的事务ID |
DB_ROLL_PTR | 7字节 | 指向Undo Log的回滚指针 |
DB_ROW_ID | 6字节 | 行隐藏ID(无主键时自增) |
-- 查看行隐藏字段(虚拟列)
SELECT `DB_TRX_ID`, -- 最后更新事务ID`DB_ROLL_PTR`, -- 指向历史版本链`DB_ROW_ID` -- 行唯一标识
FROM information_schema.INNODB_SYS_TABLES
WHERE name = 'test/t1';
2. Undo Log(版本链)
- 更新流程:每次修改前拷贝旧数据到Undo Log
- 版本链:通过DB_ROLL_PTR串联历史版本
3. ReadView(可见性判断核心)
// 源码位置:storage/innobase/include/read0types.h
class ReadView {trx_id_t m_low_limit_id; // 高水位ID(>此值的事务不可见)trx_id_t m_up_limit_id; // 低水位ID(<此值的事务可见)ids_t m_ids; // 活跃事务ID列表trx_id_t m_creator_trx_id; // 创建该ReadView的事务ID
};
三、可见性判断算法(RR隔离示例)
代码级判断逻辑:
// storage/innobase/include/read0types.h
bool changes_visible(trx_id_t id, const table_name_t& name) const {// 1. 自己修改的数据总是可见if (id == m_creator_trx_id) return true; // 2. 事务ID < 活跃事务最小ID(已提交)if (id < m_up_limit_id) return true;// 3. 事务ID >= 高水位(属于未来事务)if (id >= m_low_limit_id) return false;// 4. 事务活跃状态检查return (m_ids.find(id) == m_ids.end()); // 不在活跃列表中则可见
}
四、不同隔离级别的实现差异
隔离级别 | ReadView创建时机 | 版本链访问逻辑 |
---|---|---|
RC(读已提交) | 每次SELECT创建新ReadView | 总是读取最新已提交版本 |
RR(可重复读) | 首次SELECT创建ReadView | 复用同一视图,保持版本一致性 |
Serializable | 加锁读(不使用MVCC) | 无版本链 |
⚠️ RR防幻读机制:基于Next-Key Locking + MVCC版本快照
五、实战案例演示(RC vs RR)
-- 初始化数据
CREATE TABLE t(id INT PRIMARY KEY, v INT);
INSERT INTO t VALUES(1, 10);-- 事务1(更新数据)
START TRANSACTION;
UPDATE t SET v = 20 WHERE id = 1;-- 事务2(两次查询)
START TRANSACTION;
SELECT v FROM t WHERE id = 1; -- RC看到20|RR看到10(旧值)
COMMIT;-- 事务1提交
COMMIT;-- 事务2再次查询
SELECT v FROM t WHERE id = 1; -- RC/RR均看到20
结果对比:
步骤 | RC隔离级别结果 | RR隔离级别结果 |
---|---|---|
事务2首次查询 | 20(脏读) | 10(快照读) |
事务2二次查询 | 20(读已提交) | 10(可重复读) |
六、关键参数优化
# my.cnf配置项
innodb_undo_log_truncate = ON # 启用undo log清理
innodb_max_undo_log_size = 1G # 控制版本链长度
innodb_purge_threads = 4 # 后台清理线程数
七、MVCC的限制
- 大事务风险:长事务导致Undo Log暴涨(可能触发OOM)
- 历史版本清理:purge线程滞后可能引发性能问题
- 二级索引更新:仅主键存储版本链,二级索引通过主键回表判断可见性
📊 监控建议:定期检查SHOW ENGINE INNODB STATUS中的History list length
通过【隐藏字段+Undo版本链+ReadView】三元组配合,MySQL实现在不锁定读的情况下保证事务隔离。核心在于多版本数据存储+事务快照判断,此设计也是InnoDB高并发能力的基石。