🚀 MVCC 实现原理详解(以 MySQL InnoDB 为例)
一、什么是 MVCC?
MVCC(Multi-Version Concurrency Control,多版本并发控制) 是一种在数据库中实现高并发、读写分离的机制。
它的核心思想是:
通过为每个事务提供数据的“快照”,避免加锁,实现读写并发而互不阻塞。
二、MVCC 的核心机制
✅ 1. 读操作:读取历史版本(快照读)
- 不会阻塞写操作,也不会被写操作阻塞
- 读取的是事务开始时可见的数据快照
✅ 2. 写操作:创建新版本,不修改原数据
- 写入新版本数据,旧版本保存在 undo log 中
- 通过
roll_pointer记录旧版本地址,便于其他事务读取
三、InnoDB 中的实现细节
🧱 每行记录包含的隐藏字段
| 字段名 | 作用 |
|---|---|
trx_id |
插入或最后修改该行的事务 ID |
roll_pointer |
指向 undo log 中的旧版本记录 |
row_id |
行的唯一标识(非 MVCC 核心字段) |
📝 Undo Log(撤销日志)
当执行 UPDATE 或 DELETE 时,旧版本会被写入 undo log:
-- 初始记录:
id = 1, name = 'Tom', trx_id = 100, roll_pointer = null
-- 事务 200 执行 UPDATE name = 'Jerry'
id = 1, name = 'Jerry', trx_id = 200, roll_pointer → (Tom, trx_id=100)
四、Read View(一致性视图)
每个事务在执行第一条 SELECT 时,会创建一个 Read View,决定它能看到哪些版本的数据。
Read View 包含的信息如下:
| 属性 | 说明 |
|---|---|
| 活跃事务 ID 列表 | 当前还没提交的事务 |
| 当前事务 ID | 自己的事务 ID |
| 最小活跃事务 ID | 可见性的边界 |
| 最大活跃事务 ID | 当前系统中分配的最大事务 ID |
五、可见性判断规则
当前事务要读取一行记录时,会对其 trx_id 进行如下判断:
| 情况 | 是否可见 | 原因 |
|---|---|---|
trx_id < min_active_id |
✅ 可见 | 已提交 |
trx_id == 当前事务 ID |
✅ 可见 | 自己的数据 |
trx_id 在活跃事务列表中 |
❌ 不可见 | 尚未提交 |
trx_id > max_id |
❌ 不可见 | 是未来的事务 |
如果当前版本不可见,就会通过 roll_pointer 回溯旧版本,直到找到一个可见的版本。
六、MVCC 的优势
| 优点 | 说明 |
|---|---|
| ✅ 非阻塞读 | 避免了读写互相阻塞 |
| ✅ 高并发性能 | 适合 OLTP 类型的并发读写场景 |
| ✅ 支持事务隔离级别 | READ COMMITTED 和 REPEATABLE READ 支持 |
七、MVCC 的限制与注意事项
| 限制 | 说明 |
|---|---|
| 🚫 仅适用于特定隔离级别 | 不支持 Serializable 级别的快照读 |
🚫 对 SELECT ... FOR UPDATE 无效 |
这种加锁语句不走快照 |
| 🚫 Undo Log 空间占用 | 长事务可能导致 undo bloating |
八、总结图解
+-------------------------------------+
| 每行记录结构(数据行) |
+-------------------------------------+
| data fields |
| trx_id ← 当前事务ID |
| roll_pointer ← 指向旧版本(undo) |
+-------------------------------------+
|
↓
+--------------------+
| Undo Log |
| 存储历史版本数据 |
+--------------------+
↖
|
Read View 判断可见性










网友评论