Sunday 的面试指南

MySQL 的 MVCC 是什么?Read View 如何决定一条记录是否可见?

🧑‍💻 面试官:另一个事务修改了余额,为什么我的普通 SELECT 还读到旧值?

🙋‍♂️ 我:InnoDB 可以通过 MVCC 读取符合当前快照的版本。

🧑‍💻 面试官:版本多了以后,怎么知道应该看哪一个?是不是事务编号比我小,就都能读?

🙋‍♂️ 我:还要看创建读取视图时,那个事务是否已经提交。

🧑‍💻 面试官:那事务 BEGIN 以后才提交的记录,在 RR 下永远看不到吗?快照到底什么时候生成?

「有历史版本」只是第一步;Read View 规定当前这次读取能看见哪些事务产生的版本。

面试速答(60 秒版)

MVCC 是多版本并发控制。InnoDB 为记录保留版本信息,并通过 undo 记录回溯旧版本,让普通一致性读能够读取符合自己快照的数据,而不必总等待其他事务的写锁。

Read View 是判断版本是否可见的读取视图。它会记录创建时仍活跃的事务以及事务编号边界。自己的修改可以看见;视图创建前已经提交的修改通常可见;当时尚未提交或后来才产生的修改,对这份视图不可见。

在 READ COMMITTED 下,每次一致性读使用新的快照;在 REPEATABLE READ 下,通常第一次一致性读建立快照,后面继续使用,并不是普通 BEGIN 就一定建立。

同时,MVCC 主要解释一致性读。锁定读和写操作有自己的锁与当前读取规则,不能把所有 SQL 都当成读取旧快照。

版本链与ReadView共同控制读取

知识点详解:同一行记录,怎样找到自己能看的版本?

旧版本存在哪里?

假设账户余额原来是 100。事务 B 把它改成 80,记录会带上相应事务信息,旧值可以通过 undo 记录回溯。

可以把它理解为一条版本链:当前版本不适合读取,就沿着 undo 找更早的版本,直到找到可见的记录,或者确定这行对当前视图不存在。

undo 不只是一个与读取无关的回滚按钮。它也支撑一致性读取旧版本。历史不是无限保留,已经不再需要的版本会由清理机制处理。InnoDB 多版本说明介绍了这些记录的用途。

Read View 判断的不是“值新不新”

为了理解规则,假设视图创建时,事务 10、12 仍活跃,下一批尚未分配的编号从 15 开始。当前读者的身份另行记录。

对某个记录版本,先判断是不是自己产生的修改:自己的修改可以看见。

如果版本来自 10 之前的事务,可以认为它在视图建立前已经结束,因此可见。如果版本编号达到 15 或更大,说明它属于视图建立以后分配的事务,对当前快照不可见。

中间的编号则要检查活跃列表。比如 12 当时仍在执行,不可见;11 已经不在活跃列表,则可以看见。这里讨论的是常见用户记录的简化规则,不展开系统事务等内部细节。

因此,“编号比自己小就可见”不对:较早开始的事务,也可能在创建视图时尚未提交。真正使用的是视图边界与活跃事务,而不只是两个编号大小。MySQL 8.4 的 Read View 实现可以核对这一判断。

编号边界与活跃列表的可见规则

B 后来提交,旧视图会不会自动改变?

不会因为 B 提交,就把已有视图的活跃列表重新改写。

假设 A 已经建立了一份视图,而 B 当时还没提交。B 后来提交余额 80,A 使用原来的视图做一致性读,仍可能沿版本链读到 100。

但 A 如果自己修改了记录,能看见自己的修改。这也意味着“事务里读到的所有内容必然属于某个单一历史时刻”是过度简化,不能忽略自己的写入。

RC 与 RR,差在何时取得视图

在 READ COMMITTED 下,后续一致性读会取得新的快照。A 第二次读取时,B 已经提交,就有机会看到 80。

在 REPEATABLE READ 下,通常沿用第一次一致性读建立的快照。A 第二次仍可能看到 100。

这里的“第一次一致性读”很重要。普通 BEGIN 后还没有读,B 已经提交,再执行第一次普通 SELECT,就可能把 B 的修改包含进去。显式使用 WITH CONSISTENT SNAPSHOT 等方式时,也要结合隔离级别和实际语句理解。

这些行为针对 InnoDB 的一致性读,官方一致性读说明给出了 RC 与 RR 的区别。SELECT FOR UPDATE 不能直接套用同一套快照结论。

首次一致性读与后续读快照更新

面试官继续追问

MVCC 会让数据库完全不用锁吗?

不会。普通一致性读减少了读写之间的相互等待,但写操作、锁定读和约束检查仍然涉及锁。

两个事务同时改同一行,不能靠各自看一份旧版本就忽略写冲突。MVCC 与锁解决的事情不同。

长事务为什么影响 undo 清理?

如果某个活跃视图仍可能需要旧版本,系统就不能随便把相应历史全部清掉。

因此,长时间不结束的事务可能增加历史保留和清理压力。排查时应检查事务持续时间与相关历史指标,而不是只看当前执行的 SELECT 很快。

怎样验证自己有没有理解 RC 和 RR?

用两个独立连接,明确记录开始、第一次读、另一个事务提交、第二次读的顺序,分别测试两种隔离级别。

再改变第一次读的时机,并增加自己的写入与锁定读。必须控制时序,不能把一次偶然执行结果当成隔离规则。

面试速记卡

  • MVCC:版本信息与 undo 支撑读取符合快照的旧版本。
  • Read View:活跃事务和编号边界决定版本可见性。
  • 自己的修改:可以看见,不能忽略这一例外。
  • RC 与 RR:每次一致性读新快照,或通常沿用首次一致性读快照。
  • 边界:快照读不等于锁定读,MVCC 不会消除所有锁。
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历