mvcc巨无霸【重点】

1 ru rc

 

xxx val1 sac9   rc ru
  start sac13    

xxx val2 sac13

undo1 xxx val1 sac9

update    
   

select

start sac18

 
   

readview

[13,18]

min 13

next 19

create 13

直接返回val2
   

sac13 >= 13 < 19

&&sac13 属于[13,18]

证明该记录未提交,不可访问

 
   

查undo1

 
   

sac9 < 13

证明该记录已提交,可访问

返回val1

 

 

2 rc rr

xxx val1 sac9   rc rr
   

select

start sac11

为了保证事务内可见性,同一个事务多次select,一个事务id

 
   

readview

[11]

min 11

next 12

create 11

 
   

sac9 < 13

证明该记录已提交

返回val1

 
  start sac13    

xxx val2 sac13

undo1 xxx val1 sac9

update    
  commit 13    
   

readview

[11]

min 11

next 14

create 11

沿用readview

readview

[11]

min 11

next 12

create 11

   

sac13 >= 11 < 14

&&sac13 不属于[11]

证明该记录已提交,可访问

 sac13 > 12

该记录事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问

     返回val2  查undo1
     

 sac9 < 11

证明该记录已提交,可访问

返回val1

 以下为undo删除      
 

当前事务集合[11]

next sac 14

 

 

 

 undo0 sac13 > 11

该记录未沉默,仍对一部分事务不可见(比一部分事务readview最小值大)

它仍有传递链表节点的责任和价值

     
     commit 11  

 unco0 sac13 < 14, C为空

该记录沉默,对于当前所有事务及将来所有事务,有 sac13 < min sac

该记录对所有其它事务可见

     
 该记录的链表下一个节点undo1失去价值      
 purge线程删除undo1      

 

3 参考:

https://www.cnblogs.com/jmliao/p/13204946.html MVCC ReadView介绍

对于使用READ UNCOMMITTED隔离级别的事务来说,由于可以读到未提交事务修改过的记录,所以直接读取记录的最新版本就好了;对于使用SERIALIZABLE隔离级别的事务来说,设计InnoDB的大叔规定使用加锁的方式来访问记录(加锁是啥我们后续文章中说哈);
对于使用READ COMMITTED和REPEATABLE READ隔离级别的事务来说,都必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的,
核心问题就是:需要判断一下版本链中的哪个版本是当前事务可见的。为此,设计InnoDB的大叔提出了一个ReadView的概念,这个ReadView中主要包含4个比较重要的内容:

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

min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。

max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。

小贴士: 注意max_trx_id并不是m_ids中的最大值,事务id是递增分配的。比方说现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,m_ids就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4。

creator_trx_id:表示生成该ReadView的事务的事务id。

小贴士: 我们前边说过,只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0。胡说八道,为0还怎么搞mvcc多版本读?

有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:

如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间,那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

在MySQL中,READ COMMITTED和REPEATABLE READ隔离级别的的一个非常大的区别就是它们生成ReadView的时机不同。

READ COMMITTED —— 每次读取数据前都生成一个ReadView

REPEATABLE READ —— 在第一次读取数据时生成一个ReadView

 

 

https://zhuanlan.zhihu.com/p/166152616 MySQL 的可重复读到底是怎么实现的?图解 ReadView 机制

https://blog.csdn.net/longgeqiaojie304/article/details/98872857 Mysql隔离性之Read View MVCC ReadView介绍

 

 

4 undo在内存中,什么时候删除?

4.1 insert

commit后直接删除

4.2 update

设当前活跃事务集合C,其最小值为cmin,nextsac

当undo sac < cmin,或当C为空且undo sac < nextsac时,undo sac沉默,对将来所有事务可见,则undo sac链表下级 undo sac1可删除

 

 

 

 

Mysql Innodb中undo-log和MVCC多版本一致性读 的实现 - chouhe8007 - CSDN博客

史上最详尽,一文讲透 MVCC 实现原理 - 居士的CSDN - CSDN博客

(11条消息)mysql innodb中MVCC理解和redo,undo log详解 - harryptter的专栏 - CSDN博客

(11条消息)【MySQL】InnoDB 中 RC、RR 事务隔离级别下快照读的区别及原因 - chenghan_yang的博客 - CSDN博客

(12条消息)轻松理解MYSQL MVCC 实现机制 - 杨龙飞的博客 - CSDN博客

Mysql心路历程:两个"log"引发的"血案" - 心中的理想乡的个人页面 - OSCHINA

posted on 2020-10-13 14:03  silyvin  阅读(122)  评论(0编辑  收藏  举报