D
RuntimeScope/MySQL 面试专题/mvcc/事务与 MVCC

MySQL 面试 · MVCC Visual Lab

MVCC 可视化实验室

先别背 ReadView。先回答一个真实问题:同一行被另一个事务更新并提交后, T1 第二次普通 SELECT 到底该看到旧值还是新值?

初始数据

account(id=1, value=100)

面试官追问

T1 第二次读到 100 还是 200

T1 · T1

第一次 SELECT value

T2 · T2

UPDATE value=200

T2 · T2

COMMIT

T1 · T1

第二次 SELECT value = ?

02

MVCC 四个零件解决什么问题?

MVCC 不是凭空变出旧值。它靠四个零件合作:聚簇记录保存最新版本,DB_TRX_ID 标记谁改的,DB_ROLL_PTR 指向旧版本,ReadView 决定当前事务能看哪个版本。

聚簇记录

animation part
它解决什么问题?
这一行的最新值放在哪里?
动画里对应哪个部件?
动画中间的 account(id=1) 记录卡片。
面试时一句话
聚簇记录头部保存最新版本,快照读能不能读它,要交给 ReadView 判断。
valueDB_TRX_IDDB_ROLL_PTR

DB_TRX_ID

animation part
它解决什么问题?
怎么知道这个版本是谁改出来的?
动画里对应哪个部件?
记录卡片第二行,V200 标成 102,V100 标成 100。
面试时一句话
DB_TRX_ID 是最后修改该版本的事务 ID,ReadView 用它判断版本可见性。
V200.trx_id=102V100.trx_id=100

DB_ROLL_PTR

animation part
它解决什么问题?
最新版本不可见时,怎么找到旧值?
动画里对应哪个部件?
从聚簇记录指向 undo log 的黄色链条。
面试时一句话
DB_ROLL_PTR 指向 undo log 里的上一个版本,是快照读回溯历史版本的路径。
V200 -> undo_v1undo_v1.value=100

ReadView

animation part
它解决什么问题?
当前事务到底能看见哪个版本?
动画里对应哪个部件?
右侧规则闸门,把 trx_id 数据包送进去判定。
面试时一句话
ReadView 不是数据副本,而是一组可见性规则:活跃事务列表和上下边界。
creator=101active=[101]up=101low=102
03

主动画 Lab:ReadView 怎么挑版本?

左边看舞台,右边看解释面板。每一步都固定回答:当前发生了什么MySQL 内部做了什么面试怎么回答

故事模式:只看 A 读 → B 写 → A 再读 的主干
STEP 01 / 08阶段一 · A 第一次读
进入事务大厅
当前事务
trx_id
隔离级别
REPEATABLE READ
读类型
当前 SQL
检查版本
判断结果
下一步动作
A 第一次 SELECT
ReadView 参数
creator_trx_id
active_trx_ids
up_limit_id
low_limit_id
当前发生了什么

你正俯瞰整个执行空间。事务 T1(蓝,trx_id=101)先读 account(id=1,value=100),事务 T2(橙,trx_id=102)稍后才更新并提交,最后 T1 再读一次。

MySQL 内部做了什么

时间线只有一个核心问题:T1 第一次 SELECT 创建的 ReadView,会不会允许它在第二次 SELECT 时看到 T2 后来提交的 V200。

面试怎么回答

这道题考的是:普通 SELECT 是 consistent read / 快照读,以及 RR、RC 的 ReadView 创建时机。

TRANSACTION HALLCAM · 全景
RR · 时间冻结
RC · 实时刷新
进入事务大厅

你正俯瞰整个执行空间。事务 T1(蓝,trx_id=101)先读 account(id=1,value=100),事务 T2(橙,trx_id=102)稍后才更新并提交,最后 T1 再读一次。

A
TRX · trx_id=101
active
B
TRX · trx_id=102
idle
Snapshot Read
普通 SELECT
Current Read
UPDATE / FOR UPDATE
CLUSTERED · account(id=1)
业务字段 · payloadBIZ
id=1value=100
隐藏字段 · headerHIDDEN
DB_TRX_ID=100DB_ROLL_PTR=null
状态 · stateLATEST
undo_v1 · DB_TRX_ID=100
value=100
UNDO LOG · rollback segment
DB_ROLL_PTR
ReadView 规则闸门rv-a-1
creator101
active[101,102]
up_limit101
low_limit103
PURGE WORKER
✕ 被事务 A 的 ReadView 拦截
RR RESULT
value=100
阶段一 · A 第一次读1 / 8

本实验使用的 RR ReadView 数值

creator_trx_id = 101active_trx_ids = [101]up_limit_id = 101low_limit_id = 102
结论V200.trx_id=102,满足 102 >= low_limit_id(102),所以对 T1 的第一次 ReadView 不可见;沿 DB_ROLL_PTR 找到 V100,且 100 < up_limit_id(101),所以 RR 读到 100。

ReadView 可见性规则

1
trx_id == creator_trx_id

是当前事务自己改的 → 可见

2
trx_id < up_limit_id

快照创建前就已提交 → 可见

3
trx_id >= low_limit_id

快照创建后才开始 → 不可见

4
up_limit_id <= trx_id < low_limit_id

看是否在 active_trx_ids 里:在 → 不可见;不在 → 可见

04

快照读 vs 当前读

动画跑完以后再对齐概念:普通 SELECT 和锁定读/写不是同一条路径。

快照读SELECT ...
  1. 1普通 SELECT 是 consistent read / 快照读
  2. 2走 ReadView + undo 版本链
  3. 3最新版本不可见时,可能读历史版本
当前读UPDATE / DELETE / FOR UPDATE
  1. 1读取最新版本,不按旧 ReadView 回溯
  2. 2UPDATE / DELETE / SELECT ... FOR UPDATE 都属于这类
  3. 3参与加锁,解决读最新和写冲突问题

RC / RR 只差 ReadView 创建时机

对比项RC 读已提交RR 可重复读
ReadView 创建时机每次快照读都新建只在第一次快照读建一次
同一事务多次读可能读到不同值复用首个快照,保持一致
看到别人已提交的修改能(更新鲜)不能(更一致)

易混概念对比

概念是什么RR 下的行为
快照读普通 SELECT,读 ReadView 可见版本复用首个 ReadView
当前读锁定读/写,读最新已提交版本读最新 + 加锁
ReadView判断版本可见性的快照第一次快照读时建立
undo 版本链保存旧版本供回溯长事务会拖住 purge
05

高频面试题与标准回答

现在再回到面试题:按时间线、版本链、隔离级别三段回答。

RR 下事务 A 为什么第二次 SELECT 仍读旧值?

面试官意图:考你能否用 ReadView 和 undo 版本链解释,而不是说 MySQL 把写事务锁住了。

A 第一次快照读建立 ReadView 后,RR 会复用这个快照。B 后续提交的新版本对这个 ReadView 不可见,A 会沿 undo 版本链找到旧版本。

RC 和 RR 的 ReadView 创建时机有什么区别?

面试官意图:考你能否区分快照新鲜度和事务一致性。

RC 每次 consistent read 建新 ReadView,所以能看到已提交的新版本;RR 同一事务复用第一次 consistent read 的 ReadView。

快照读和当前读怎么区分?

面试官意图:考你是否知道普通 SELECT 和锁定读/写语句走不同并发控制路径。

普通 SELECT 多数是快照读,按 ReadView 读可见版本;当前读读取最新版本,如 UPDATE、DELETE、SELECT FOR UPDATE,会配合锁控制并发。

RR 下 T1 第一次快照读建立 ReadView:creator_trx_id=101、active_trx_ids=[101]、up_limit_id=101、low_limit_id=102。

T2 更新后的版本 trx_id=102,满足 102 >= low_limit_id(102),对 T1 的第一次 ReadView 不可见,所以 T1 沿 DB_ROLL_PTR 找到 V100。

V100.trx_id=100,满足 100 < up_limit_id(101),因此 RR 下 T1 第二次仍读到 100。

如果是 RC,每次读新建 ReadView,就会读到 200。

06

常见误区、工程判断与复习清单

最后检查是否会说人话,也会做工程判断。

常见误区

  • · 误区:ReadView 一定在 START TRANSACTION 时创建。
  • · 误区:MVCC 不加锁,所以写写也不会冲突。
  • · 误区:RR 完全靠 MVCC 解决所有幻读,锁不重要。

工程判断

  • · 避免长事务包住大量业务逻辑,否则 undo 和 purge 压力会累积。
  • · 读一致性要求高时关注 RR 的快照复用;读新鲜度要求高时理解 RC 的行为。
  • · 写路径冲突要看锁,不能用 MVCC 解释所有并发现象。

通关检查

0/5 已掌握

追问链

  • Q事务 A 自己 UPDATE 后再 SELECT 会看到什么?
  • Q长事务为什么会拖住 undo purge?
  • Q当前读为什么不能直接读旧版本?
07

引用台账与 source lock

这部分默认折叠,避免打断主学习流。

展开引用台账 / source lock

引用台账

  • MVCC 与 ReadView 机制
  • InnoDB Multi-Versioning / Consistent Read

source lock

INNODB-JCY-2MYSQL-INDEX-USAGE