全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-15 8 分钟 ✍️ juanwangdev

MySQL MVCC多版本并发控制

MVCC(Multi-Version Concurrency Control)通过保存数据多个版本,实现读写不阻塞。

MVCC 核心概念

组件说明
Undo Log存储数据旧版本,形成版本链
Read View读视图,决定能看到哪个版本
事务ID每个事务有唯一递增ID

Undo Log 版本链

SQL
-- 每条记录包含隐藏字段
-- DB_TRX_ID: 最后修改的事务ID
-- DB_ROLL_PTR: 回滚指针,指向Undo Log中的旧版本
-- DB_ROW_ID: 行ID(无主键时生成)

-- 示例:数据修改过程
INSERT INTO users VALUES (1, '张三');  -- trx_id = 100
UPDATE users SET name = '李四' WHERE id = 1;  -- trx_id = 101
UPDATE users SET name = '王五' WHERE id = 1;  -- trx_id = 102

-- 版本链结构(从新到旧)
-- 当前数据: name='王五', trx_id=102, roll_ptr→undo1
-- undo1: name='李四', trx_id=101, roll_ptr→undo2
-- undo2: name='张三', trx_id=100, roll_ptr→NULL

Read View 结构

SQL
Read View 包含:
- m_ids: 创建 Read View 时活跃事务ID列表
- min_trx_id: m_ids 中最小值
- max_trx_id: 下一个待分配事务ID
- creator_trx_id: 创建该 Read View 的事务ID

版本可见性判断

SQL
数据版本 trx_id:
1. trx_id < min_trx_id → 可见(已提交)
2. trx_id >= max_trx_id → 不可见(之后新事务)
3. trx_id 在 m_ids 中 → 不可见(活跃未提交)
4. trx_id 不在 m_ids 中且 trx_id < max_trx_id → 可见(已提交)
5. trx_id == creator_trx_id → 可见(自己修改)

RC 与 RR 的 Read View 差异

SQL
-- READ COMMITTED: 每次 SELECT 创建新 Read View
-- 事务A                          事务B
START TRANSACTION;               START TRANSACTION;
SELECT * FROM users;             UPDATE users SET name='x';
-- Read View 1                   COMMIT;
SELECT * FROM users;
-- Read View 2,能看到事务B的修改

-- REPEATABLE READ: 第一次 SELECT 创建 Read View,后续复用
-- 事务A                          事务B
START TRANSACTION;               START TRANSACTION;
SELECT * FROM users;             UPDATE users SET name='x';
-- Read View 1                   COMMIT;
SELECT * FROM users;
-- 仍用 Read View 1,看不到事务B的修改
COMMIT;
SELECT * FROM users;  -- 新 Read View,能看到修改

MVCC 工作流程

text
-- 查询流程
SELECT name FROM users WHERE id = 1;

-- 1. 获取当前事务的 Read View
-- 2. 获取最新版本数据
-- 3. 判断 trx_id 是否可见
-- 4. 不可见则通过 roll_ptr 找上一版本
-- 5. 重复判断直到找到可见版本或到链尾

MVCC 与锁的关系

操作MVCC
普通读使用 MVCC无锁
锁定读不使用加行锁
写操作不使用加行锁
text
-- 普通读(快照读):使用 MVCC
SELECT * FROM users WHERE id = 1;

-- 锁定读(当前读):不使用 MVCC,加锁
SELECT * FROM users WHERE id = 1 FOR UPDATE;
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;

MVCC 解决的问题

  1. 读写不阻塞:读操作不加锁,写操作不阻塞读
  2. 解决脏读:只看到已提交版本
  3. 解决不可重复读:RR 级级 Read View 复用,版本不变

MVCC 不解决幻读,但 InnoDB 通过间隙锁+临键锁在 RR 级别解决幻读。

要点总结

  • MVCC 通过 Undo Log 版本链实现多版本数据
  • Read View 决定事务能看到哪个版本
  • RC 每次 SELECT 新建 Read View
  • RR 复用首次 SELECT 的 Read View
  • 快照读用 MVCC,当前读加锁
  • MVCC 解决脏读和不可重复读,不解决幻读

📝 发现内容有误?点击此处直接编辑

← 上一篇 MySQL 索引类型
下一篇 → MySQL 事务ACID特性
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库