深入理解 InnoDB 的 MVCC:原理、Read View 与可见性判断

深入理解 InnoDB 的 MVCC:原理、Read View 与可见性判断

摘要

多版本并发控制(Multi-Version Concurrency Control,MVCC)是 InnoDB 实现高并发读的核心机制之一:读操作通常不需要加行锁即可读到「一致性快照」,写操作通过版本链与 undo log 维护历史版本。本文从行记录隐藏字段、undo 版本链、Read View 与可见性算法入手,区分快照读与当前读,并辅以流程图梳理判断逻辑,最后简要讨论隔离级别与 MVCC 的边界。


一、为什么需要 MVCC

在传统「读写互斥」模型下,读多写少的 OLTP 场景容易因锁竞争拖慢查询。MVCC 的思路是:为每行数据维护多个版本,事务读取时根据规则选择其中一个版本,从而:

  • 普通读(快照读)多数情况下避免对数据行加锁,减少阻塞;
  • 仍通过锁与日志保证正确性,与读在版本维度上解耦。

InnoDB 的 MVCC 主要服务于读已提交(RC)与可重复读(RR) 下的快照读;串行化等场景会更多依赖锁。


二、InnoDB 行记录与隐藏列

聚簇索引叶子节点中的每行(逻辑上)除用户列外,还包含与 MVCC 相关的隐藏字段(概念上):

隐藏字段 含义
DB_TRX_ID 最近一次插入或更新该行的事务 ID
DB_ROLL_PTR 指向 undo log 中旧版本行的指针(回滚指针)
DB_ROW_ID 无主键/非空唯一索引时用于生成聚簇索引行 ID(与 MVCC 可见性无直接关系)

更新一行时,InnoDB 会生成 undo 记录,旧值通过 DB_ROLL_PTR 连成版本链,新版本成为当前行上的「当前版本」。


三、undo log 与版本链(简图)

undo 链(从新到旧)
当前行(聚簇索引页)
Row: trx_id, roll_ptr → ...
Undo1
Undo2
Undo3

读请求不会随意遍历整条物理链到「无穷旧」,而是通过 Read View 决定在逻辑上哪一版对该事务可见。


四、Read View 是什么

Read View 是某次快照读建立的一份「一致性读视图」,其中保存了生成时刻的事务 ID 快照信息,用于判断:当前行某版本的 trx_id 对本读事务是否可见

典型实现中会关心(不同版本源码字段名可能略有差异,语义一致):

  • 活跃事务 ID 列表 m_ids:生成 Read View 时仍处于活跃状态的事务集合;
  • 最小活跃事务 ID min_trx_id
  • 系统分配给下一个事务的 ID max_trx_id(或等价上界);
  • 创建该 Read View 的事务 ID creator_trx_id

五、可见性判断核心流程

对某行版本,其事务 ID 记为 trx_id,当前 Read View 记为 RV。下面给出教学中常用的判定顺序(与源码细节顺序一致即可,不必死记变量名)。








取该行版本的 trx_id
trx_id == creator_trx_id?
可见:本事务自己的修改
trx_id < RV.min_trx_id?
可见:在 RV 创建前已提交
trx_id >= RV.max_trx_id?
不可见:晚于 RV 的事务产生
trx_id 在 m_ids 中?
不可见:活跃未提交
可见:已提交且不在活跃集
沿 roll_ptr 取上一版本继续判断
返回该版本数据

要点

  • 若当前版本对读事务不可见,则沿 DB_ROLL_PTR 向 undo 方向找更旧的版本,直到可见或链结束。
  • RCRR 的重要差异之一:在 InnoDB 中,同一事务内 RC 往往每条语句 可能使用新的 Read View;RR 则在首次快照读时固定 Read View(具体以官方文档与当前版本行为为准),因此出现「不可重复读」与「可重复读」的差异。

六、快照读 vs 当前读

类型 典型语句 是否走 MVCC 快照
快照读 普通 SELECT(无锁读) 是,按 Read View 选版本
当前读 SELECT ... FOR UPDATE/LOCK IN SHARE MODEUPDATEDELETE 最新已提交版本并加锁(语义需要看到最新)

因此:MVCC 解决的是「一致性快照读」的路径当前读仍依赖锁与最新版本,和「避免幻读」等话题要结合 Next-Key Lock 等机制一起看(RR 下范围锁等)。


七、与隔离级别的关系(概念对齐)

隔离级别
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

  • RC:语句级一致性读视图(多次 SELECT 可能看到别的事务新提交)。
  • RR :事务级一致性快照(同一事务多次 SELECT 看到同一快照;InnoDB 下对幻行还有间隙锁等配合,需区分「快照可见性」与「锁防插入」)。

八、MVCC 的边界与常见误解

  1. MVCC 不是「完全无锁」:写操作、当前读仍可能加锁;垃圾回收、purge 线程清理旧版本也有成本。
  2. 长事务:长时间不提交的事务可能使旧版本无法及时 purge,导致 undo 膨胀与空间压力。
  3. 只读事务:若能明确只读,可合理使用「一致性快照」语义;仍要注意元数据锁、DDL 等其它因素。

九、小结

  • MVCC 通过 trx_id + undo 版本链 + Read View 实现快照读路径上的一致性视图
  • 可见性 由 Read View 与版本 trx_id 比较决定,不可见则沿 roll_ptr 回溯。
  • 区分 快照读当前读 ,并结合 RC/RR 理解「何时换 Read View」。
  • 生产环境需关注 长事务、purge、索引设计 等与版本堆积相关的问题。
相关推荐
Jul1en_2 小时前
Java 集合判空方法对比
java·spring boot·算法·spring
kyriewen2 小时前
你还在给每个图片父元素加类名?CSS :has() 让选择器“逆天改命”
前端·css·面试
golang学习记2 小时前
IDEA 2026.1:这些 核心功能免费开放!
java·ide·intellij-idea
我就是你毛毛哥2 小时前
Docker 安装 Jenkins JDK8 版
java·docker·jenkins
爱敲代码的菜菜2 小时前
【Redis】Redis基本操作
java·数据库·redis·缓存·hash·zset
编码忘我2 小时前
java之线程池
java·后端·面试
handsomethefirst2 小时前
【算法与数据结构】【面试经典150题】【题46-题50】
数据结构·算法·面试
程序员水自流2 小时前
【AI大模型第13集】Transformer底层架构原理详细介绍(核心组件拆解分析)
java·人工智能·架构·llm·transformer
岁岁种桃花儿2 小时前
kubenetes从入门到上天系列第二十六篇:Kubernetes的Istio服务网格实战
java·kubernetes·istio