MVCC 版本链 通俗易懂讲解

MVCC(多版本并发控制)是 InnoDB 存储引擎实现并发读写的核心机制,而版本链就是 MVCC 能工作的 "底层账本"------ 简单说,它是把同一条数据的多次修改记录串联起来的链表,让不同事务能同时读取、修改数据,还不互相干扰。

一、先搞懂:版本链是怎么来的?

InnoDB 的每行数据除了我们自己定义的列(比如 id、name),还藏着两个隐藏字段(核心):

  • DB_TRX_ID:记录最后一次修改这条数据的事务 ID;
  • DB_ROLL_PTR:回滚指针,指向这条数据上一个版本的位置(版本链的 "链扣")。

当数据被修改时,InnoDB 不会直接覆盖原数据,而是做这几步:

  1. 把原数据复制一份,作为 "旧版本" 存到undo 日志(回滚日志)里;
  2. 更新当前行的 DB_TRX_ID 为当前修改事务的 ID;
  3. 把当前行的 DB_ROLL_PTR 指向刚生成的旧版本;
  4. 重复修改的话,新的旧版本会继续链接到上一个旧版本后面,形成 "版本链"。

举个通俗例子:

  • 初始状态:数据行(id=1, name = 张三),DB_TRX_ID=0(无修改),DB_ROLL_PTR=null(无旧版本);
  • 事务 1(ID=100)修改 name 为 "李四":→ 原数据(张三)被存到 undo 日志,成为版本 1;→ 当前行 DB_TRX_ID=100,DB_ROLL_PTR 指向版本 1;
  • 事务 2(ID=200)再修改 name 为 "王五":→ 当前行(李四)被存到 undo 日志,成为版本 2,且版本 2 的 DB_ROLL_PTR 指向版本 1;→ 当前行 DB_TRX_ID=200,DB_ROLL_PTR 指向版本 2;
  • 最终版本链:当前行(王五)→ 版本 2(李四)→ 版本 1(张三)。

二、版本链的核心作用:让读写不冲突

MVCC 会结合事务隔离级别 + Read View(读视图),通过版本链实现:

  1. 读操作(SELECT):不用加锁,直接在版本链里找 "当前事务能看到的最新版本";比如隔离级别是 "可重复读" 时,事务启动后生成 Read View,后续不管其他事务怎么改数据,都只认启动时能看到的版本,避免 "不可重复读"。
  2. 写操作(UPDATE/DELETE):只修改当前版本,旧版本保留在版本链,既不影响读,又能支持事务回滚(回滚时从版本链找回旧数据)。

三、关键细节:版本链和 Read View 的配合

Read View 是事务读取数据时的 "可见性规则",包含 4 个核心值:

  • m_ids:当前活跃的事务 ID 列表;
  • min_trx_id:活跃事务中最小的 ID;
  • max_trx_id:下一个要分配的事务 ID;
  • creator_trx_id:当前事务的 ID。

读取数据时,会遍历版本链,判断每个版本的 DB_TRX_ID 是否符合可见性:✅ 版本的 DB_TRX_ID <min_trx_id:这个版本是 "已提交事务" 改的,可见;❌ 版本的 DB_TRX_ID >= max_trx_id:这个版本是 "未来事务" 改的,不可见;❌ 版本的 DB_TRX_ID 在 m_ids 里:这个版本是 "活跃未提交事务" 改的,不可见;✅ 其他情况:可见。

四、版本链的清理:undo 日志的回收

版本链不是永久存在的 ------ 当没有任何事务需要访问这些旧版本时,InnoDB 的 purge 线程会清理掉没用的 undo 日志(旧版本),避免磁盘占用过大。比如所有事务都已提交,且都不需要回滚到某个旧版本,这个版本就会被清理,版本链也会缩短。

总结

MVCC 版本链的核心逻辑:✅ 数据修改不覆盖,而是生成新版本、链接旧版本,形成版本链;✅ 读操作通过 Read View 在版本链找 "可见版本",不用加锁;✅ 写操作只改当前版本,旧版本支持回滚和并发读;最终实现了 InnoDB 的 "读不加锁、读写不冲突",大幅提升并发性能。

相关推荐
万邦科技Lafite2 小时前
京东店铺所有商品API接口指南讲解
java·开发语言·数据库·电商开放平台·淘宝开放平台
YDS8292 小时前
MyBatis-Plus —— 扩展功能详解
数据库·mybatis
zzz大王2 小时前
sql 50 题 21-25
数据库·sql
线程A2 小时前
Python中 session flush 和 commit 的区别
数据库·python·oracle
博语小屋4 小时前
实现简单日志
linux·服务器·数据库·c++
程序员小白条11 小时前
0经验如何找实习?
java·开发语言·数据结构·数据库·链表
liulilittle11 小时前
C++ 浮点数封装。
linux·服务器·开发语言·前端·网络·数据库·c++
郭涤生11 小时前
QT 架构笔记
java·数据库·系统架构
韩立学长11 小时前
基于Springboot流浪动物领养网站0kh2iyb4(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端