Read View 是什么?#

Read View(读视图)是 InnoDB 存储引擎中实现 MVCC(多版本并发控制) 的核心数据结构。


本质#

Read View 本质上是一个事务快照,记录了某个时刻系统中活跃事务的状态,用来判断某条记录的哪个版本对当前事务是可见的


Read View 的结构#

type ReadView struct {
    m_low_limit_id  uint64  // 高水位:生成时下一个待分配的事务ID
                             // >= 此值的事务,对我不可见
    m_up_limit_id   uint64  // 低水位:活跃事务中最小的事务ID
                             // < 此值的事务,对我可见
    m_creator_trx_id uint64 // 创建此 Read View 的事务ID
    m_ids           []uint64 // 生成时,系统中所有活跃(未提交)事务的ID列表
}

可见性判断规则#

当前事务读取某行数据时,会拿该行版本链上每个版本的 trx_id 与 Read View 比较:

版本的 trx_id
      │
      ├─ < m_up_limit_id        → 可见(已提交的老事务)
      │
      ├─ >= m_low_limit_id      → 不可见(生成之后才开始的事务)
      │
      └─ 在中间区间内
            ├─ 在 m_ids 中      → 不可见(生成时还未提交)
            └─ 不在 m_ids 中    → 可见(生成时已提交)

Read View 何时创建?#

这取决于事务隔离级别

隔离级别 Read View 创建时机
RC(读已提交) 每次 SELECT 都创建一个新的 Read View
RR(可重复读) 事务中第一次 SELECT 时创建,之后复用

这就是为什么:

  • RC 能读到其他事务已提交的最新数据(不可重复读)
  • RR 整个事务期间看到的是同一份快照(可重复读)

与 Undo Log 的关系#

Read View 只是"判官",真正的多版本数据存储在 Undo Log 中。

当前行数据 → trx_id=100(不可见)
     │
     └──► Undo Log 版本链 → trx_id=80(不可见)
                    │
                    └──► trx_id=60(可见,返回此版本)

Read View 沿着版本链不断回溯,直到找到第一个可见版本为止。


Read View 伪代码#

package main

type ReadView struct {
	// 创建 Read View 时,当前活跃事务列表
	MIds []int64

	// 活跃事务中最小的事务 id
	MinTrxID int64

	// 下一个将要分配的事务 id
	MaxTrxID int64

	// 当前事务自己的 id
	CreatorTrxID int64
}

// 判断某个版本的 trxID 对当前 Read View 是否可见
func (rv *ReadView) IsVisible(trxID int64) bool {
	// 1. 自己创建/修改的版本,总是可见
	if trxID == rv.CreatorTrxID {
		return true
	}

	// 2. 如果 trxID < MinTrxID
	// 说明这个版本对应的事务在 Read View 创建前就已经提交
	if trxID < rv.MinTrxID {
		return true
	}

	// 3. 如果 trxID >= MaxTrxID
	// 说明这个版本对应的事务是在 Read View 创建后才开启的
	if trxID >= rv.MaxTrxID {
		return false
	}

	// 4. 如果 trxID 在 [MinTrxID, MaxTrxID) 之间
	// 需要判断它是否在活跃事务列表中
	if rv.inMIds(trxID) {
		// 在活跃列表中,说明创建 Read View 时它还没提交
		return false
	}

	// 不在活跃列表中,说明已经提交
	return true
}

func (rv *ReadView) inMIds(trxID int64) bool {
	for _, id := range rv.MIds {
		if id == trxID {
			return true
		}
	}
	return false
}

总结#

Read View 就是事务开始读数据时拍的一张"系统活跃事务快照",用它来决定 Undo Log 版本链上哪个历史版本是当前事务该看到的。

InnoDB 的 MVCC 会为事务创建 Read View,用来判断记录版本的可见性。 判断规则是:自己的修改总是可见;若版本的 trx_id 小于 Read View 的 min_trx_id,则说明该版本由快照创建前已提交事务生成,可见; 若 trx_id 大于等于 max_trx_id,则说明该版本由快照创建后才启动的事务生成,不可见; 若 trx_id 位于两者之间,则再判断其是否在 m_ids 活跃事务列表中,在则不可见,不在则可见。

本站总访问量  ·  访客数
你的IP 获取中…