跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

MVCC多版本并发控制:链表变量在数据库事务中的应用

MVCC的核心是基于版本链的数据可见性控制机制,而非编程意义上的链表变量;它通过隐藏字段(DB_TRX_ID、DB_ROLL_PTR)与Undo Log逻辑构建单向版本链,并结合Read View判断事务可见性,实现快照读、避免读写阻塞。 MVCC 的核心不是“链表变量”,而是 基于版本链的数据可见性控制机制 。数据库里并不存在编程语言中那种可直接赋值、遍历的链表变量(如
LinkedList
),所谓“版本链”是 InnoDB 通过隐藏字段和 Undo Log 逻辑组织起来的历史数据结构 ,本质是一条由回滚指针串起的单向链表,仅在事务读取判断时被内部遍历,不对用户暴露。 下面从实际作用出发,说清楚它在事务中怎么用、为什么重要: 版本链是怎么形成的 每行记录背后有三个关键隐藏字段:
DB_TRX_ID
:最后一次修改该行的事务 ID
DB_ROLL_PTR
:指向 Undo Log 中前一版本的指针(即“链表节点”的连接方式)
DB_ROW_ID
:行唯一标识(非核心,可忽略) 当事务执行
UPDATE
或
DELETE
: 原始数据不覆盖,而是把旧值写入 Undo Log 新记录的
DB_TRX_ID
设为当前事务 ID,
DB_ROLL_PTR
指向刚写入的 Undo Log 位置 这样就自然形成一条从最新版 → 上一版 → 更早版的单向链 例如:
balance = 1000(事务99创建) ↓ DB_ROLL_PTR balance = 800(事务101修改) ↓ DB_ROLL_PTR balance = 500(事务102修改,尚未提交)
Read View 如何用这条链做可见性判断 事务执行快照读(普通
SELECT
)时,InnoDB 生成一个 Read View,包含:
m_ids
:当前活跃未提交事务 ID 列表
min_trx_id
:
m_ids
中最小值
max_trx_id
:下一个待分配事务 ID
creator_trx_id
:本事务自己的 ID 然后沿着版本链从新到旧扫描,对每个版本按规则判断是否可见: 若版本
DB_TRX_ID < min_trx_id
→ 属于已提交的“过去”, 可见 若版本
DB_TRX_ID == creator_trx_id
→ 本事务自己改的, 可见 若版本
DB_TRX_ID ∈ m_ids
→ 属于其他未提交事务, 不可见 其他情况(如 ≥
max_trx_id
)→ 视为“未来”版本, 不可见 直到找到第一个可见版本,就返回它——这就是你看到的“一致性快照”。 不同隔离级别下,链的使用方式不同 读已提交(RC) :每次
SELECT
都生成新 Read View,所以同一事务内两次查询可能看到不同版本(因为中间有别的事务提交了) 可重复读(RR) :只在 第一次
SELECT
时生成 Read View ,后续查询复用它,因此能保证“可重复读”——哪怕别的事务已提交新版本,链上更老但符合 Read View 规则的版本仍被选中 注意:链不是万能的,也有边界 它解决不了 幻读 (新插入的行不在原版本链上,需配合间隙锁) Undo Log 不清理会导致版本链过长、空间膨胀,影响性能和 purge 效率
DELETE
后的记录虽逻辑删除,仍保留在链中,直到所有依赖它的事务结束 本质上,版本链是 MVCC 的物理载体,Read View 是它的决策规则。两者配合,让数据库在不加锁的前提下,给每个事务发一张“定制快照”,既并发又一致。

相关文章