innodb如何实现mvcc的

InnoDB 实现 MVCC(多版本并发控制)的机制主要依赖于 Undo Log(回滚日志)Read View(读视图)隐藏的事务字段。以下是具体实现步骤和原理:


1. 核心数据结构

InnoDB 的每一行数据(聚簇索引记录)包含两个隐藏字段:

  • DB_TRX_ID:最近修改该行的事务 ID。
  • DB_ROLL_PTR:指向该行旧版本数据的回滚指针(即 Undo Log 的地址)。

2. Undo Log 与版本链

  • Undo Log 的作用
    每次对数据进行修改(INSERT/UPDATE/DELETE),InnoDB 会生成 Undo Log,记录修改前的数据镜像。

  • 版本链的构建
    通过 DB_ROLL_PTR 字段,将同一行数据的多个版本按修改顺序链接成链表。
    示例

    plaintext 复制代码
    当前行 → [版本3: trx_id=300, roll_ptr → 版本2]  
                ↑  
    版本2 → [trx_id=200, roll_ptr → 版本1]  
                ↑  
    版本1 → [trx_id=100, roll_ptr → NULL]

3. Read View 的生成

当事务执行 一致性读 (如 SELECT)时,InnoDB 为其生成一个 Read View,包含以下信息:

  • m_ids:当前活跃(未提交)的事务 ID 列表。
  • min_trx_idm_ids 中的最小事务 ID。
  • max_trx_id:下一个即将分配的事务 ID(即当前最大事务 ID +1)。
  • creator_trx_id:创建该 Read View 的事务 ID(仅当该事务自身有修改时存在)。

4. 数据可见性判断规则

对于某一数据行的版本,判断其对当前事务是否可见的规则如下:

  1. 版本的事务 ID < min_trx_id
    该版本已提交,可见。
  2. 版本的事务 ID ≥ max_trx_id
    该版本由未来事务生成,不可见。
  3. min_trx_id ≤ 版本的事务 ID < max_trx_id
    • 若版本的事务 ID 不在 m_ids,说明该事务已提交,可见。
    • 若版本的事务 ID m_ids,说明该事务未提交,不可见。
  4. 版本的事务 ID = creator_trx_id
    该版本由当前事务自身修改,可见。

5. MVCC 的查询流程

  1. 定位最新数据行:通过聚簇索引找到当前行的最新版本。
  2. 遍历版本链 :从最新版本开始,根据 DB_ROLL_PTR 回溯旧版本。
  3. 可见性检查:对每个版本应用 Read View 规则,找到第一个可见的版本。

示例

假设事务 A(trx_id=200)的 Read View 中:

  • m_ids = [100, 300]
  • min_trx_id=100, max_trx_id=400

遍历某行的版本链:

  • 版本3(trx_id=300) :在 m_ids 中 → 不可见。
  • 版本2(trx_id=200) :等于 creator_trx_id → 可见(若事务 A 修改了该行)。
  • 版本1(trx_id=100) :在 m_ids 中 → 不可见。
  • 版本0(trx_id=50) :小于 min_trx_id → 可见。

最终事务 A 读取到版本0。


6. 不同隔离级别的实现差异

  • 读已提交(Read Committed)
    每次执行 SELECT 时生成新的 Read View,看到已提交的最新数据。
  • 可重复读(Repeatable Read)
    事务内第一次 SELECT 时生成 Read View,后续复用该视图,保证多次读取一致性。

7. Undo Log 的清理

  • Insert Undo Log:事务提交后立即删除(不参与 MVCC)。
  • Update/Delete Undo Log :需保留至所有可能访问旧版本的事务结束(通过 purge 线程异步清理)。

8. MVCC 与锁的协同

  • 写操作(UPDATE/DELETE)
    即使使用 MVCC,写操作仍需加锁(如行锁)避免脏写。
  • 读操作(SELECT)
    默认无锁,通过 MVCC 读取快照版本。若需锁定读,可加锁(如 SELECT ... FOR UPDATE)。

总结

InnoDB 通过以下机制实现 MVCC:

  1. 版本链 :通过 DB_ROLL_PTR 链接数据的历史版本。
  2. Read View:判断事务可见性的依据。
  3. Undo Log:存储历史版本数据,支持版本链回溯。
  4. 隔离级别适配:通过动态生成或复用 Read View 实现不同隔离级别。
plaintext 复制代码
# MVCC 执行示例
事务A(trx_id=200)读取某行数据:
1. 找到最新版本(trx_id=300)。
2. 检查 Read View:m_ids=[100, 300], min=100, max=400。
3. trx_id=300 在 m_ids 中 → 不可见。
4. 回溯到版本2(trx_id=200),等于 creator_trx_id → 可见。
相关推荐
互联网搬砖老肖39 分钟前
运维打铁: MongoDB 数据库集群搭建与管理
运维·数据库·mongodb
典学长编程1 小时前
数据库Oracle从入门到精通!第四天(并发、锁、视图)
数据库·oracle
积跬步,慕至千里2 小时前
clickhouse数据库表和doris数据库表迁移starrocks数据库时建表注意事项总结
数据库·clickhouse
极限实验室2 小时前
搭建持久化的 INFINI Console 与 Easysearch 容器环境
数据库
白仑色3 小时前
Oracle PL/SQL 编程基础详解(从块结构到游标操作)
数据库·oracle·数据库开发·存储过程·plsql编程
程序猿小D4 小时前
[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的个人财务管理系统,推荐!
java·数据库·mysql·spring·毕业论文·ssm框架·个人财务管理系统
钢铁男儿5 小时前
C# 接口(什么是接口)
java·数据库·c#
__风__6 小时前
PostgreSQL kv(jsonb)存储
数据库·postgresql
轩情吖6 小时前
Qt的第一个程序(2)
服务器·数据库·qt·qt creator·qlineedit·hello world·编辑框
Databend6 小时前
Databend 产品月报(2025年6月)
数据库