全网最详细MVCC讲解,一篇看懂( 四 )

事务可见性示意图:

全网最详细MVCC讲解,一篇看懂

文章插图
图片
RC 和 RR 下的 Read ViewRC 和 RR 下生成 Read View 的时机是有所差异的:
  • RC:每次 SELECT 数据前都生成一个ReadView 。
  • RR:只在第一次读取数据时生成一个ReadView,后面会复用第一次生成的 。
正因为RC 和 RR生成 Read View 的时机不同 , 导致两个级别下看到的数据会不一致 。
举例说明,假设数据初始状态如下:
有 A,B,C 三个事务 , 执行顺序如下:
 
事务A(事务ID: 100)
事务B(事务ID: 200)
事务C(事务ID: 300)
T1
begin
 
 
T2
 
begin
begin
T3
update user set name="小王" where id=1
 
 
T4
update user set name="小红" where id=1
 
select * from user where id = 1
T5
commit
update user set name="小黑" where id=1
 
T6
 
update user set name="小白" where id=1
select * from user where id = 1
T7
 
commit
 
T8
 
 
select * from user where id = 1
T9
 
 
commit
T10
 
 
 
RC 下的 Read ViewT4时刻
我们来看 T4 时刻的情况,此时 事务A 和 事务B 都还没提交,所以活跃的事务ID,即 m_ids 为:[100,200],四个字段的值分别如下:
字段

m_ids
[100 , 200]
m_creator_trx_id
300
m_low_limit_id
400
m_up_limit_id
100
T4时刻的版本链如下:
全网最详细MVCC讲解,一篇看懂

文章插图
图片
依据我们之前说的可见性原则,事务C最终看到的应该是  name = "小明"  的数据,理由如下:
最新记录的 DB_TRX_ID 为 100,既不小于 m_up_limit_id,也不大于 m_low_limit_id,也不等于 m_creator_trx_id 。
落在了黄区:
全网最详细MVCC讲解,一篇看懂

文章插图
图片
DB_TRX_ID 存在于 m_ids 列表中,故不可见,顺着版本链继续往下 。
根据 DB_ROLL_PTR 找到 undo log 中的前一版本记录,前一条记录的 DB_TRX_ID 还是 100,还是不可见 , 继续往下 。
继续找前一条 DB_TRX_ID为 1 , 满足 1 < m_up_limit_id,可见,所以事务C 查询到数据为  name = "小明"   。
T6时刻
T6时候的版本链如下:
全网最详细MVCC讲解,一篇看懂

文章插图
图片
T6时刻,会再次生成新的 Read View,四个字段的值分别如下:
字段

m_ids
[200]
m_creator_trx_id
300
m_low_limit_id
400
m_up_limit_id
200
根据可见性原则,最终T6时刻事务C 查询到数据为  name = "小红"  。
T8时刻
T8时刻的版本链和T6时刻是一致的,不同的是 Read View,因为T8时刻会再生成一个 Read View,四个字段的值分别如下:
字段

m_ids
[]
m_creator_trx_id
300
m_low_limit_id
400
m_up_limit_id
400
根据可见性原则,最终T8时刻事务C 查询到数据为  name = "小白"  。
总结一下,事务C在 RC 级别下各个时刻看到的数据如下:
时刻
name
T4
小明


推荐阅读