read view是innodb在首次快照读时生成的内存结构,非配置项、不持久;rr级别复用同一view实现可重复读,rc级别每次快照读重建,当前读(如select for update)则完全绕过。

Read View 不是配置项,也不是你手动创建的对象,它是 InnoDB 在执行快照读(比如普通 SELECT)时自动生成的内存结构,决定“这一行数据对当前事务是否可见”。理解它,关键不是背规则,而是看清它怎么被触发、字段怎么参与判断、以及哪些操作根本绕过它。
Read View 什么时候真正生成?
很多人以为 BEGIN 或 START TRANSACTION 就锁定了 Read View,其实不是。它只在事务中第一次执行快照读时才生成——也就是第一次不带锁的 SELECT。
- 空事务(只
BEGIN不查)不会生成 Read View,后续SELECT才触发 -
SELECT ... FOR UPDATE或UPDATE是当前读,不走 Read View,也不刷新它 - RR 隔离级别下,这个 Read View 会被整个事务复用;RC 下每次
SELECT都重建
Read View 的四个核心字段怎么参与可见性判断?
每个 Read View 包含四个关键字段:creator_trx_id、m_ids、min_trx_id(或 up_limit_id)、max_trx_id(或 low_limit_id)。它们不是独立起作用,而是一起构成判定链:
-
creator_trx_id:当前事务自己的 ID。如果某行的DB_TRX_ID == creator_trx_id,直接可见(自己改的,必须看到) -
m_ids:生成时刻所有未提交事务 ID 的快照列表。若某行的DB_TRX_ID在这个列表里,说明它由还没提交的事务写入,不可见 -
min_trx_id:m_ids中最小值。若某行的DB_TRX_ID ,说明它在 Read View 生成前就已提交,可见 -
max_trx_id:下一个将分配的事务 ID。若某行的DB_TRX_ID >= max_trx_id,说明它在 Read View 生成后才开始,不可见
为什么长事务会让 Read View “卡住” undo log 清理?
因为 m_ids 是生成时刻的活跃事务快照,只要有一个事务长期不提交(比如开了事务但忘了 COMMIT),它的 ID 就会一直留在后续所有新 Read View 的 m_ids 中。
- InnoDB 认为“这个旧版本可能还被某个事务需要”,所以不敢清理对应的 undo log
- 磁盘空间持续增长,
information_schema.innodb_trx里能看到trx_started时间极早的事务 - 更隐蔽的是:
min_trx_id被卡住不前进,拖慢整个实例的 purge 进程
哪些查询根本不用 Read View?
Read View 只服务于快照读。以下操作完全绕过它,直接读最新版本或加锁:
-
SELECT ... FOR UPDATE和SELECT ... LOCK IN SHARE MODE:当前读,走聚簇索引最新记录 + 加锁 -
UPDATE、DELETE、INSERT:当前读,基于最新已提交版本做修改 -
READ UNCOMMITTED隔离级别:不使用 Read View,直接读DB_TRX_ID最新的行(哪怕未提交) -
SERIALIZABLE隔离级别:默认给所有SELECT加共享锁,也不依赖 Read View
最易被忽略的一点是:Read View 的生命周期完全绑定于“快照读行为”,而非事务本身。一个事务可以有多个 Read View 吗?在 RC 下可以;在 RR 下不行——但如果你在 RR 事务中先执行了当前读(如 SELECT ... FOR UPDATE),再执行快照读,那个快照读仍用最初生成的 Read View,不会因锁读而重置。这个细节,线上排查幻读或不可重复读时经常成为盲区。











