什么是ReadView,什么样的ReadView可见 ?

一、定义

ReadView 是 InnoDB 中一个至关重要的概念,它是实现MVCC的基础,同时他也是支持不同的事务隔离级别的基础,同时提高系统的并发能力和性能。


它到底是干啥的?简单来说,其实就是一句话:读视图(Read View) 主要来帮我们解决可见性的问题的, 即它会来告诉我们本次事务能看到哪个 undolog版本,不能看到哪个undolog版本


我们都知道,MySQL中用不同的事务隔离级别,比如我们常见的 RR 和 RC,RR要求在一个事务中,多次读取的结果是保持一致的,而RC则要求每次都要读取到最新的值。


那么,具体如何实现的RR和RC的读数据的时候的不同现象,就是这个快照


在可重复读(Repeatable Read)级别下,读视图(ReadView)会在事务中第一次 select 语句执行时生成,在本事务中第二次 select 语句时会复用第一次的读视图(ReadView),只有在本事务中对数据进行更改才会更新读视图


在读已提交(Read Committed)级别下,每次读取都会重新生成一个读视图(ReadView),总是读取行的最新版本


在mysql5.6中的 ReadView 的定义更加直观:

也就是说,在 Read View 中有几个重要的属性:

  • trx_ids表示在生成 ReadView 时当前系统中活跃的读写事务的 事务id 列表

  • low_limit_id应该分配给下一个 事务的id 值

  • up_limit_id未提交的事务中最小的事务 id

  • creator_trx_id创建这个 Read View 的事务id


trx_ids 中包含了 low_limit_idup_limit_id 的信息,其实 trx_ids = [up_limit_id,low_limit_id)


(但是需要注意,它并不一定连续,只是会包含 up_limit_id,并且小于 low_limit_id,比如他可能是5, 7, 8, 11),


并且你没看错,up_limit_id 就是表示最低水位,low_limit_id 就是表示最高水位

网上还有些资料这里有 min_trx_id、max_trx_id、m_ids等的说法,我翻了下源码5.6、5.7、8.0,并没有找到出处。就先不纠结了,以源码为准。


也就是说,每一次读取数据的时候(RC情况下),都会生成一个 ReadView,并且在其中记录上 trx_ids(包含了[up_limit_id, low_limit_id))和 creator_trx_id


那么,一个事务能看到哪个 undolog版本,不能看到哪个undolog版本该如何判断呢 ?


假如一个 ReadView 的内容为:

trx_ids = [5,6,8)

low_limit_id = 8

up_limit_id = 5

creator_trx_id = 7

假设当前事务要读取某一个undolog版本的记录行,该记录行的事务id为:db_trx_id,那么,就有以下几种情况了:

  • 1、db_trx_id < up_limit_id,即小于5的事务,说明该事务 db_trx_id 在生成ReadView之前就已经提交了,那么该事务的结果就是可见的

  • 2、db_trx_id > low_limit_id,即大于8的事务,说明该事务db_trx_id 在生成 ReadView 后才生成,所以该事务的结果就是不可见的

  • 3、up_limit_id < db_trx_id < low_limit_id,即大于等于5,小于8,这种情况下,会再拿事务id 和 Read View 中的 trx_ids 进行逐一比较

    • 如果,事务id 在 trx_ids 列表中,如6,那么表示在当前事务开启时,这个事务还是活跃的,那么这个记录对于当前事务来说应该是不可见的

    • 如果,事务id 不在 trx_ids 列表中,如7,那么表示的是在当前事务开启之前,其他事务对数据进行修改并提交了,所以,这条记录对当前事务就应该是可见的

    • 当然这里有个例外情况,那就是这个 db_trx_id = creator_trx_id,说明当前undolog版本的记录行是由创建这个 Read View 的事务提交的,那么就肯定是可见的


总结一下就是,一个事务,能看到的是在它开始之前就已经提交的事务的结果,而未提交的结果都是不可见的。

posted @ 2025-06-06 11:39  jock_javaEE  阅读(66)  评论(0)    收藏  举报