mysql-MVCC机制

结论

在对版本链中的事务ID进行比较时,有以下规则:

在这里插入图片描述
我们可以简单理解为在左边区域的,都是可见的;在中间区域的部分,如果是当前事务ID操作的,对当前事务可见;在右边区域的,都是不可见的

  1. 如果版本链中的事务ID,落在最左边区域(tx_id < min_id),那表示当前版本是已经提交的事务,是可见的

  2. 如果版本链中的事务ID,是落在右边部分(tx_id > max_id),表示这个版本是由将来启动的事务生成的(将来的事务,也就是当前session生成事务ID之后,有其他session生成的新的事务ID),是不可见的

  3. 如果版本链中的事务ID,是落在中间区域(min_id <= tx_id <= max_id),那分为两种情况
    3.1 如果当前版本链的事务ID,不在readview的数组中,表示这个事务ID,是已经提交的事务,是可见的
    3.2 如果当前版本链的事务ID,在readview的数组中,表示这个版本的事务ID是由未提交的事务创建的,是不可见的;但是如果当前连接的事务ID == 版本链中的事务ID,是可见的,因为这种表示是当前连接创建的事务,对自己当然是可见的

  4. 对于删除的操作,可以认为是update的特殊情况,在执行删除操作的时候,会把版本链上最新的数据复制一份,然后将tx_id修改为删除操作对应的tx_id,同时在该记录的头信息中(record_header)的delete_flag标识标记为true,来表示当前记录已经被删除,在查询的时候,会判断delete_flag标识,如果为true,则不返回

应用

MVCC,Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问

mvcc机制,涉及到一个readview的概念;readview中维护的是当前session在生成事务ID的时候,产生的读视图,这个读视图中存储的是当前数据库系统中活跃的事务ID,这里活跃的事务ID是指:已经开启了事务,但是未提交的连接对应的事务Id
ReadView中主要包含4个比较重要的内容:

  1. m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
  2. min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
  3. max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
  4. creator_trx_id:表示生成该ReadView的快照读操作产生的事务id。

在每次执行select查询的时候,会根据生成的readview和对应的事务版本链进行对比,从而得到查询结果

版本链是指:在每个事务对一条记录进行update操作的时候,会依次生成一条版本信息,记录着当前更新之后的值和进行更新操作的事务ID,以及对应的回滚指针

在RC隔离级别下,readview是在每次进行快照读的时候(可以简单理解为每次查询的时候),都会获取最新的readview
在RR隔离级别下,readview是以第一次进行快照读时,获取到readview为准,不会每次获取最新的

扫描二维码关注公众号,回复: 12613159 查看本文章

以下,我们来验证mvcc版本链的查询操作
需要注意:
1.以下场景一、二、三;是在RR隔离级别下验证
2.事务ID是在第一次执行select的时候生成的,所以,我们在begin执行之后,会执行一个select语句,比如:(select * from other_table;);这样可以保证先生成一个事务ID

场景一

在这里插入图片描述
图1
在SessionD,执行select语句的时候,此时,由于10、20、30、40,此时的事务都是未提交的事务,所以都在readview中,所以会获取到tx_id为5的记录,也就是此时获取到的age是20

场景二

在这里插入图片描述
对于sessionC来说,在执行select查询的时候,此时的版本链是这样的

在这里插入图片描述
那此时SessionC在执行查询的时候,readview是(10,20,30,40);会依次从下往上进行判断
此时,所有的tx_id(除了tx_id为5的),都是在readview中,所以都是不可见的,所以返回的是tx_id为5的值:20

场景三

在这里插入图片描述

这种场景,sessionD在执行select,查询的时候,此时活跃的事务ID只有10和30,所以:此时的readview就是(10,30,40);
对应的版本链依旧是场景一中的顺序

  • 在执行select的时候,会依次从版本链中,开始查找
  • 先找到tx_id为30的,此时30还在readview中,说明tx_id为30的事务,未提交,且不是sessionD的事务,所以不可见;继续向下查找
  • 找到tx_id为20的,此时20 > 10;且小于 < 40;但是20不在readview中,说明此时该事务已经提交,所以可见,就会返回22

场景四

读已提交和可重复读的区别:就在于获取readview的时机:
读已提交是在每次执行select查询的时候,获取最新的readview
而可重复读是以第一次执行select查询时,获取到的readview为准
下面这个例子,就验证了
在这里插入图片描述
在RC级别下,如果SessionB事务提交之后,sessionC再次执行select查询操作,此时是可以获取到最新的age:22的
原因就是:sessionC中第二次执行select查询的时候,会获取最新的readview,此时活跃的事务ID是(10,30,40)
在版本链中进行查找的时候:
在这里插入图片描述
事务ID为30记录,是在readview中,所以此时不可见,
事务ID为20的记录,虽然20 > 10,但是此时事务ID为20,不存在readview中,所以:此时的事务ID为20的session,已经提交了事务,可见;这也就是上面结论中3.1对应的场景

参考这位大佬的笔记学习的 添加链接描述

猜你喜欢

转载自blog.csdn.net/CPLASF_/article/details/109579770