Read View 是 InnoDB 为实现 MVCC 而构造的事务可见性规则表,不是数据快照;它仅包含 creator_trx_id、m_ids、min_trx_id、max_trx_id 四个字段,用于判断行版本可见性,不存储任何数据。

Read View 不是数据快照,而是一张“事务可见性规则表”——它不存数据,只记哪些事务 ID 该被忽略、哪些版本该被跳过。
Read View 是什么?不是什么?
它不是内存中的一份表数据副本,也不是磁盘上的某个文件。它是 InnoDB 在执行普通 SELECT(即非加锁读)时,为判断某行的哪个历史版本对当前事务可见,而临时构造的一组规则。核心字段只有四个:m_ids(活跃事务 ID 列表)、min_trx_id(m_ids 中最小值)、max_trx_id(下一个将分配的事务 ID)、creator_trx_id(当前事务自己的 ID)。
常见误解是把它当成“数据库某一时刻的完整拷贝”,其实它连一行数据都不保存,全靠和每行的隐藏字段 DB_TRX_ID 对比 + 沿着 DB_ROLL_PTR 往 Undo Log 版本链上回溯来定位可见版本。
Read View 什么时候生成?取决于隔离级别
生成时机直接决定事务能否看到其他事务的提交结果:
-
READ COMMITTED:每次执行SELECT前都新建一个ReadView,所以第二次查询可能看到第一次没看到的数据 → 出现不可重复读 -
REPEATABLE READ(MySQL 默认):仅在事务中**第一次执行SELECT** 时生成,后续所有快照读都复用它 → 同一事务内多次读同一行,结果必然一致 -
READ UNCOMMITTED:根本不生成ReadView,直接读最新版本 → 可能脏读 -
SERIALIZABLE:退化为加锁读(如SELECT ... FOR UPDATE),ReadView不起作用
注意:BEGIN 或 START TRANSACTION 不触发生成;真正启动事务并首次执行快照读(比如 SELECT * FROM t)才生成。如果事务 BEGIN 后等了 10 秒再查,那它的 ReadView 就会包含这 10 秒内新开启但未提交的所有事务 ID。
Read View 如何判断某行是否可见?四条规则
InnoDB 拿某行的 DB_TRX_ID(最后修改它的事务 ID)和 ReadView 四个字段比对,顺序如下:
- 若
DB_TRX_ID == creator_trx_id→ 自己改的,一定可见 - 若
DB_TRX_ID → 这行在 <code>ReadView创建前就已提交,可见 - 若
DB_TRX_ID >= max_trx_id→ 这行是“未来事务”写的(逻辑上不可能存在,但用于排除),不可见 - 若
min_trx_id → 查 <code>DB_TRX_ID是否在m_ids中:在 → 那个事务还没提交,不可见;不在 → 已提交,可见
不满足任一可见条件,就顺着 DB_ROLL_PTR 往 Undo Log 版本链上找上一个版本,继续比对,直到找到或链尾。这个过程完全无锁、无等待。
容易被忽略的关键点
UPDATE/DELETE 才会生成 Undo Log 版本链,INSERT 不会;ReadView 只影响快照读(普通 SELECT),不影响当前读(如 SELECT ... LOCK IN SHARE MODE);max_trx_id 不是“最大活跃事务 ID”,而是“下一个将分配的事务 ID”,源码里叫 low_limit_id;m_ids 是生成瞬间的快照,之后其他事务提交或回滚,都不会改变当前事务的 ReadView 内容。


















