深入了解 MySQL InnoDB 中 MVCC 与锁的具体协作流程

你想深入了解 MySQL InnoDB 中 MVCC 与锁的具体协作流程,这是理解两者配合的关键。接下来我会从 InnoDB 实现 MVCC 的核心组件入手,一步步拆解它的工作原理,以及和锁如何分工协作,全程用通俗的语言 + 实例,让你彻底搞懂。

一、MVCC 的核心实现基础(3 个关键组件)

InnoDB 不是凭空实现 MVCC 的,而是依赖 3 个核心机制,这是理解后续流程的前提:

1. 行记录的隐藏字段

InnoDB 会为每一行数据(除了用户定义的字段)自动添加 3 个隐藏字段,用来标记版本信息:

隐藏字段 作用
DB_TRX_ID 最后一次修改(插入 / 更新)该行数据的事务 ID(递增的唯一编号)
DB_ROLL_PTR 回滚指针,指向该行数据的历史版本(存储在 undo log 中)
DB_ROW_ID 行唯一 ID(如果表没有主键 / 唯一索引,InnoDB 会自动生成)

可以把这 3 个字段理解为:给每行数据贴了一个 "版本标签",记录了 "谁最后改的""历史版本在哪"。

2. Undo Log(回滚日志)

Undo Log 是 MVCC 的 "版本仓库",作用有两个:

  • 存储数据的历史版本:每次修改数据(UPDATE/DELETE),InnoDB 会先把修改前的数据拷贝到 Undo Log 中,形成一个版本链;
  • 事务回滚:如果事务执行失败,可通过 Undo Log 恢复数据到修改前的状态。

举个例子:

  • 事务 100 插入一行数据:DB_TRX_ID=100DB_ROLL_PTR=null(无历史版本);
  • 事务 200 更新这行数据:InnoDB 先把 "事务 100 版本" 拷贝到 Undo Log,再修改当前行的 DB_TRX_ID=200DB_ROLL_PTR 指向 Undo Log 中的 "100 版本";
  • 事务 300 再更新这行数据:同理,Undo Log 中会新增 "200 版本",当前行 DB_TRX_ID=300DB_ROLL_PTR 指向 "200 版本";
  • 最终形成版本链:当前行(300)→ Undo Log 中的 200 版本 → Undo Log 中的 100 版本。
3. Read View(读视图)

Read View 是 MVCC 的 "版本筛选规则",每个事务在执行快照读(普通 SELECT)时,会生成一个 Read View,用来判断当前事务能 "看到" 哪个版本的数据。

Read View 包含 4 个核心参数:

  • m_ids:当前活跃的事务 ID 列表(即还没提交的事务);
  • min_trx_idm_ids 中的最小值;
  • max_trx_id:系统下一个要分配的事务 ID(大于当前所有已分配的);
  • creator_trx_id:生成这个 Read View 的事务 ID。

核心判断规则(判断版本链中的某个版本是否可见):

  1. 如果版本的 DB_TRX_ID < min_trx_id:该版本是 "已提交事务" 修改的,可见;
  2. 如果版本的 DB_TRX_ID >= max_trx_id:该版本是 "未来事务" 修改的,不可见;
  3. 如果 min_trx_id ≤ DB_TRX_ID < max_trx_id
    • DB_TRX_IDm_ids 中(事务还没提交):不可见;
    • DB_TRX_ID 不在 m_ids 中(事务已提交):可见;
  4. 特殊:如果版本的 DB_TRX_ID = creator_trx_id(自己修改的):可见。

二、MVCC + 锁 协作的完整实例(可重复读隔离级别)

为了让你更直观理解,我们用一个具体场景拆解(假设初始数据:id=1,name="张三",DB_TRX_ID=0DB_ROLL_PTR=null):

场景:两个并发事务
时间 事务 A(trx_id=101) 事务 B(trx_id=102)
T1 开始事务 -
T2 SELECT * FROM t WHERE id=1;(快照读) -
T3 - 开始事务
T4 - UPDATE t SET name="李四" WHERE id=1;(写操作,加行锁)
T5 SELECT * FROM t WHERE id=1;(快照读) -
T6 - 提交事务
T7 SELECT * FROM t WHERE id=1;(快照读) -
T8 SELECT * FROM t WHERE id=1 FOR UPDATE;(当前读) -
T9 提交事务 -
分步拆解:
1. T2:事务 A 第一次快照读
  • 生成 Read View:
    • m_ids=[101](只有自己活跃),min_trx_id=101max_trx_id=103creator_trx_id=101
  • 读取 id=1 的行:当前行 DB_TRX_ID=0 < min_trx_id=101,可见;
  • 结果:name="张三"(无锁,不阻塞任何操作)。
2. T4:事务 B 执行 UPDATE(写操作)
  • 锁的作用 :InnoDB 对 id=1 的行加行级排他锁(X 锁),防止其他事务同时修改这行;
  • MVCC 的作用
    • 把当前行(DB_TRX_ID=0,name="张三")拷贝到 Undo Log,形成版本 0;
    • 修改当前行:name="李四",DB_TRX_ID=102DB_ROLL_PTR 指向 Undo Log 中的版本 0;
  • 此时版本链:当前行(102)→ 版本 0(0)。
3. T5:事务 A 第二次快照读
  • 可重复读隔离级别下,事务 A 复用 T2 生成的 Read View(m_ids=[101]min_trx_id=101);
  • 检查当前行的 DB_TRX_ID=102
    • 101 ≤ 102 < 103,且 102 不在 m_ids=[101] 中?但因为是复用 Read View,InnoDB 会沿着版本链找可见版本;
    • 找到 Undo Log 中的版本 0(DB_TRX_ID=0 < 101),可见;
  • 结果:还是 name="张三"(读不阻塞写,且保证可重复读)。
4. T6:事务 B 提交
  • 释放 id=1 行的排他锁(锁的使命完成);
  • Undo Log 不会立即删除(后续由 purge 线程清理),仍为 MVCC 提供版本。
5. T7:事务 A 第三次快照读
  • 仍复用 T2 的 Read View,因此还是读取版本 0;
  • 结果:依然是 name="张三"(可重复读的核心体现)。
6. T8:事务 A 执行当前读(SELECT ... FOR UPDATE)
  • 锁的作用:此时不走 MVCC,直接加行级排他锁,读取最新版本;
  • MVCC 不生效 :跳过版本链,直接读取当前行(DB_TRX_ID=102,name="李四");
  • 结果:name="李四"(当前读必须拿到最新数据,且加锁防止其他写操作)。

三、锁和 MVCC 的分工总结(InnoDB 视角)

环节 锁的角色 MVCC 的角色
快照读(普通 SELECT) 无锁(完全不参与) 生成 Read View,遍历版本链找可见版本
写操作(UPDATE/DELETE/INSERT) 加行级排他锁,防止写冲突 生成数据新版本,维护版本链
当前读(SELECT ... FOR UPDATE) 加行级锁,阻塞其他写操作 不生效,直接读取最新版本
事务隔离级别 仅靠锁只能实现 "读未提交 / 串行化" 实现 "读已提交 / 可重复读" 核心逻辑

总结

  1. MVCC 的核心实现三要素:行隐藏字段(版本标记)、Undo Log(版本仓库)、Read View(版本筛选规则),三者共同实现了 "快照读";
  2. 锁与 MVCC 的协作逻辑:锁负责解决 "写冲突"(排他锁),MVCC 负责解决 "读写阻塞" 和 "读一致性"(快照读);
  3. 关键区分:普通 SELECT 走 MVCC(快照读、无锁),写操作 / 锁定读走锁(当前读、加锁),二者结合实现了高效且一致的并发控制。
相关推荐
AC赳赳老秦几秒前
量化交易脚本开发:DeepSeek生成技术指标计算与信号触发代码
数据库·elasticsearch·信息可视化·流程图·数据库架构·memcached·deepseek
何中应3 分钟前
Redis的两个小错误
数据库·redis·缓存
落羽凉笙5 分钟前
Python基础(4)| 详解程序选择结构:单分支、双分支与多分支逻辑(附代码)
android·服务器·python
携欢11 分钟前
portswigger靶场之修改序列化数据类型通关秘籍
android·前端·网络·安全
Dovis(誓平步青云)18 分钟前
《Linux 核心 IO 模型深析(中篇):探索Cmake与多路转接的高效实现poll》
linux·运维·服务器·数据库·csdn成长记录
DBA小马哥20 分钟前
MongoDB迁移全解析:国产多模融合下的平滑替代实践
数据库·mongodb·dba
进阶小白猿21 分钟前
Java技术八股学习Day14
java·数据库·学习
jnrjian22 分钟前
Oracle username 集成 AD
数据库·oracle
施嘉伟25 分钟前
Oracle重建控制文件技术总结
数据库·oracle
小光学长26 分钟前
基于ssm的美容院会员管理系统xnbnpp45(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库