MySql中MVCC的底层原理

MySQL 中 MVCC 的底层原理详解(InnoDB 引擎)

MVCC 全称 Multi-Version Concurrency Control(多版本并发控制),是 InnoDB 引擎实现高并发的核心技术之一。它允许读写操作互不阻塞,大大提升了数据库的并发性能。


1. MVCC 解决的核心问题

在没有 MVCC 之前:

  • 读操作会加共享锁(S 锁)
  • 写操作会加排他锁(X 锁)
  • 读写互相阻塞 → 并发度低

MVCC 的目标实现“读不阻塞写,写不阻塞读”,同时保证事务隔离级别(重点是 可重复读)。


2. MVCC 的底层实现机制

2.1 隐藏字段(每行记录都有的系统列)

InnoDB 在每行记录中额外存储以下隐藏字段:

字段名长度作用
DB_TRX_ID6 字节事务 ID:最后修改该行的事务 ID
DB_ROLL_PTR7 字节回滚指针:指向 Undo Log 的指针,用于找历史版本
DB_ROW_ID6 字节行 ID:当表没有主键时,InnoDB 自动生成的聚簇索引 ID

2.2 Undo Log(回滚日志)

  • 当事务修改一行记录时,InnoDB 会把旧版本写入 Undo Log。
  • 新版本的 DB_ROLL_PTR 指向旧版本。
  • 形成一条版本链(从最新版本通过回滚指针指向越来越老的版本)。

版本链结构示例

当前记录 (TRX_ID=100) → Undo Log (TRX_ID=90) → Undo Log (TRX_ID=80) → ...

3. ReadView(读视图)—— MVCC 的灵魂

ReadView 是每个 SELECT 操作(快照读)在开始时生成的一个一致性视图,它决定了当前事务能看到哪些版本。

ReadView 主要包含以下信息:

  • m_ids:当前活跃(未提交)的事务 ID 列表
  • min_trx_id:活跃事务中最小的 ID
  • max_trx_id:下一个要分配的事务 ID(当前系统最大事务 ID + 1)
  • creator_trx_id:创建该 ReadView 的事务 ID

版本可见性判断规则(非常重要):

当事务读取一行记录时,会从最新版本开始,沿着版本链遍历,找到第一个对当前事务可见的版本:

  1. 如果记录的 TRX_ID < min_trx_id可见(在 ReadView 创建前已提交)
  2. 如果记录的 TRX_ID == creator_trx_id可见(当前事务自己修改的)
  3. 如果记录的 TRX_IDm_ids 列表中 → 不可见(活跃事务,未提交)
  4. 如果记录的 TRX_ID >= max_trx_id不可见(在 ReadView 创建后才启动的事务)

找到可见版本后,直接返回该版本的数据。


4. 快照读 vs 当前读

读取方式SQL 示例是否使用 MVCC说明
快照读SELECT * FROM table普通 SELECT,使用 MVCC 读历史版本
当前读SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE
INSERTUPDATEDELETE
读取最新版本,并加锁

可重复读(RR)隔离级别下,同一个事务中所有普通 SELECT 都使用同一个 ReadView,从而实现可重复读。


5. MVCC 在不同隔离级别下的行为

隔离级别ReadView 创建时机说明
读未提交每次 SELECT 都新建 ReadView几乎无 MVCC 效果
读已提交每次 SELECT 都新建 ReadView每次读都能看到最新已提交数据
可重复读(默认)事务第一次 SELECT 时创建,整个事务复用同一个事务内数据一致
串行化不使用 MVCC,直接加锁最严格

6. MVCC 的工作流程完整示例

假设事务 A(ID=100)执行:

START TRANSACTION;
SELECT * FROM user WHERE id = 1;   -- 生成 ReadView

同时事务 B(ID=101)执行:

UPDATE user SET name = '新名字' WHERE id = 1;  -- 创建新版本,旧版本进 Undo Log

事务 A 再次执行 SELECT

  • 看到的是旧版本(因为事务 B 未提交,ID=101 在 ReadView 的 m_ids 中)
  • 事务 B 提交后,事务 A 再次 SELECT 依然看到旧版本(RR 隔离级别下 ReadView 不变)

7. MVCC 的优缺点

优点

  • 大幅提升并发度(读写不冲突)
  • 实现非阻塞读
  • 支持可重复读隔离级别

缺点

  • Undo Log 占用额外存储空间(需定期 purge)
  • 版本链过长时,查找历史版本会有一定开销
  • 无法完全解决幻读(MySQL 通过 Gap Lock + MVCC 共同解决)

8. 相关知识点扩展

  • Undo Log 分为 Insert Undo 和 Update Undo
  • Purge 线程:清理已无用的 Undo Log 版本
  • 多版本并发控制只针对普通 SELECT(快照读)
  • 聚簇索引中保存完整记录,二级索引中保存主键 + TRX_ID 等

总结
MySQL 的 MVCC 核心就是 “隐藏字段 + Undo 版本链 + ReadView 可见性判断”。通过为每一行维护多个版本,并让读操作通过 ReadView 选择合适的版本,实现高并发下的数据一致性。


需要我继续深入讲解以下哪个部分?

  • MVCC + Gap Lock 如何共同解决幻读
  • Undo Log 的物理结构与 Purge 机制
  • RR vs RC 隔离级别下 MVCC 的实际差异(带案例)
  • 源码层面(trx_sys、ReadView 结构体等)

随时告诉我!

文章已创建 5321

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部