Read View 是事务执行快照读时生成的可见性判定依据,非全局共享;它在事务首次快照读时创建(RR 级复用,RC 级每次 SELECT 新建),包含 m_ids、m_low_limit_id、m_up_limit_id 和 m_creator_trx_id 四个核心字段,仅记录活跃事务 ID 快照,不保存数据本身。

Read View 是什么,它在哪儿生成
Read View 不是全局共享的内存结构,而是每个事务在执行快照读(比如普通 SELECT)时按需生成的快照元信息。它本质是一个只读的数据结构,记录了当前时刻系统中活跃事务的 ID 列表和一些边界值。
关键点在于:它不保存数据本身,只保存“谁正在干活”的快照——也就是哪些事务还没提交、哪些已经结束。真正被读取的老版本数据,存在 undo log 里,靠 roll_pointer 连成版本链。
-
read_view在事务第一次执行快照读时创建(REPEATABLE READ下复用;READ COMMITTED下每次SELECT都新建) - 它包含四个核心字段:
m_ids(活跃事务 ID 列表)、m_low_limit_id(下一个将分配的事务 ID)、m_up_limit_id(活跃事务中最小 ID)、m_creator_trx_id(本事务自己的 ID) - 它不参与写操作,也不影响其他事务的执行流程,纯读时判定用
Read View 如何判断一行数据是否可见
当 InnoDB 找到某行记录的最新版本后,会顺着 roll_pointer 往上遍历版本链,对每个版本检查其 trx_id 是否满足可见性规则。这个判断完全依赖当前事务的 read_view 内容。
- 若版本的
trx_idm_up_limit_id → 该事务已提交,且早于当前事务开始前就结束了 → 可见 - 若
trx_id∈m_ids→ 正在运行中,未提交 → 不可见 - 若
trx_id≥m_low_limit_id→ 属于未来事务(ID 比当前最大还大)→ 不可见 - 若
trx_id==m_creator_trx_id→ 当前事务自己写的 → 可见(即使未提交)
这个判定过程不加锁、不阻塞,是纯逻辑计算,所以快照读才能做到高性能。
RC 和 RR 的 Read View 差异在哪
区别不在结构,而在生命周期和复用策略——这直接导致两次 SELECT 看到的数据是否一致。
-
READ COMMITTED:每次执行SELECT都新建read_view,因此能立刻看到其他事务新提交的数据 → 解决脏读,但有不可重复读 -
REPEATABLE READ:仅在事务内**第一次**快照读时生成read_view,后续所有SELECT都复用它 → 同一事务中多次读结果一致,但可能看不到中间已提交的变更 - 注意:
UPDATE/DELETE/SELECT ... FOR UPDATE是当前读,不走read_view,而是直接读最新行并加锁
容易忽略的边界情况
很多人以为 REPEATABLE READ 能彻底避免幻读,其实不然——Read View 只管“已有行”的版本可见性,不管“新插入的行”是否存在。
- 幻读主要发生在
INSERT场景,而read_view对新插入的记录没有感知能力(因为没它的trx_id和roll_pointer) - InnoDB 实际靠**间隙锁(Gap Lock)** +
next-key lock来堵住插入,不是靠read_view本身 - 如果关闭唯一索引或使用非等值条件(如
WHERE id > 5),间隙锁可能失效,幻读风险回升 -
read_view中的m_low_limit_id是“下一个将分配的事务 ID”,不是当前最大已用 ID,这点在高并发下会影响判定精度


















