MySQL 数据库 MVCC 机制
-
- 一句话定义(面试版)
- [一、MVCC 解决了什么问题?](#一、MVCC 解决了什么问题?)
-
- [有了 MVCC 之后](#有了 MVCC 之后)
- [二、MVCC 的核心组成(3 个必考点)](#二、MVCC 的核心组成(3 个必考点))
-
- [1️⃣ 隐藏字段(每一行都有)](#1️⃣ 隐藏字段(每一行都有))
- [2️⃣ Undo Log(版本链)](#2️⃣ Undo Log(版本链))
- [3️⃣ Read View(一致性视图)](#3️⃣ Read View(一致性视图))
- [三、MVCC 是如何"读数据"的?](#三、MVCC 是如何“读数据”的?)
- [四、快照读 vs 当前读(理解 MVCC 的关键)](#四、快照读 vs 当前读(理解 MVCC 的关键))
-
- [1️⃣ 快照读(Snapshot Read)](#1️⃣ 快照读(Snapshot Read))
- [2️⃣ 当前读(Current Read)](#2️⃣ 当前读(Current Read))
- [五、RC vs RR 中 MVCC 的不同](#五、RC vs RR 中 MVCC 的不同)
- [六、MVCC 不能解决什么?](#六、MVCC 不能解决什么?)
- 七、一个完整例子(一步看懂)
-
- 初始数据
- [事务 A(RR)](#事务 A(RR))
- [事务 B](#事务 B)
- [事务 A 再读](#事务 A 再读)
- [八、MVCC 的优缺点总结](#八、MVCC 的优缺点总结)
-
- [✅ 优点](#✅ 优点)
- [❌ 代价](#❌ 代价)
- 九、一句话总结
在 MySQL(准确说是 InnoDB 存储引擎) 中,MVCC(Multi-Version Concurrency Control,多版本并发控制) 是一种 在不加锁或少加锁的情况下,实现高并发读写并保证事务隔离性 的机制。
一句话定义(面试版)
MVCC 是 InnoDB 通过保存数据的多个版本,让读操作读取历史版本,从而避免读写冲突、提升并发性能的一种机制。
一、MVCC 解决了什么问题?
在没有 MVCC 的情况下:
- 读要加锁
- 写要加锁
- 读写互相阻塞
👉 并发性能非常差
有了 MVCC 之后
| 操作 | 是否阻塞 |
|---|---|
| 读 ↔ 读 | 不阻塞 |
| 读 ↔ 写 | 不阻塞 |
| 写 ↔ 写 | 阻塞 |
👉 读写并发能力大幅提升
二、MVCC 的核心组成(3 个必考点)
1️⃣ 隐藏字段(每一行都有)
InnoDB 每一行都有两个隐藏字段:
| 字段 | 作用 |
|---|---|
trx_id |
最近一次修改该行的事务 ID |
roll_pointer |
指向 undo log 中旧版本的指针 |
2️⃣ Undo Log(版本链)
每次 UPDATE / DELETE:
-
原数据不会被立即覆盖
-
旧版本写入 undo log
-
多个版本形成一条 版本链
当前行 → v3 → v2 → v1(undo log)
3️⃣ Read View(一致性视图)
Read View 决定:
当前事务能"看到"哪个版本的数据
它包含:
m_ids:当前活跃事务 ID 列表min_trx_id:最小活跃事务 IDmax_trx_id:下一个将分配的事务 IDcreator_trx_id:创建者事务 ID
Read View 更多介绍参考《MySQL 数据库 Read View 详解》
三、MVCC 是如何"读数据"的?
可见性规则(核心)
当事务读取一行时:
1️⃣ 拿到该行的 trx_id
2️⃣ 与 Read View 比较
判断规则简化为:
| 条件 | 是否可见 |
|---|---|
| trx_id < min_trx_id | ✅ 已提交 |
| trx_id > max_trx_id | ❌ 未来事务 |
| trx_id 在 m_ids 中 | ❌ 未提交 |
| 否则 | ✅ |
如果不可见:
👉 通过 roll_pointer 找 旧版本
四、快照读 vs 当前读(理解 MVCC 的关键)
1️⃣ 快照读(Snapshot Read)
sql
SELECT * FROM user WHERE id = 1;
- 走 MVCC
- 读历史版本
- 不加锁
2️⃣ 当前读(Current Read)
sql
SELECT * FROM user WHERE id = 1 FOR UPDATE;
UPDATE user SET name='A' WHERE id = 1;
- 读最新版本
- 不走 MVCC
- 一定加锁
五、RC vs RR 中 MVCC 的不同
| 项目 | RC | RR |
|---|---|---|
| Read View | 每条 SELECT 一个 | 事务级 |
| 是否可重复读 | ❌ | ✅ |
| 普通 SELECT | 快照读 | 快照读 |
| 幻读处理 | Read View | 锁 + MVCC |
📌 注意:
MVCC 只对普通 SELECT 生效
六、MVCC 不能解决什么?
❌ 写写冲突
❌ 当前读的幻读
❌ SERIALIZABLE 下的并发问题
👉 所以 InnoDB 仍然需要:
- 行锁
- Gap Lock
- Next-Key Lock
七、一个完整例子(一步看懂)
初始数据
id=1, balance=100
事务 A(RR)
sql
START TRANSACTION;
SELECT balance FROM account WHERE id=1;
👉 读到 100
事务 B
sql
UPDATE account SET balance=200 WHERE id=1;
COMMIT;
事务 A 再读
sql
SELECT balance FROM account WHERE id=1;
- RR:仍读
100 - RC:读
200
📌 都没加锁
八、MVCC 的优缺点总结
✅ 优点
- 高并发
- 减少锁
- 读写不互斥
❌ 代价
- 占用 undo log 空间
- 长事务影响性能
- 实现复杂
九、一句话总结
MVCC 是 InnoDB 通过 undo log + Read View,让普通 SELECT 在不加锁的情况下读取一致性数据的核心机制。