Mysql MVVC笔记

什么是MVVC,为什么要用它

在mysql的InnoDB不同事务隔离级别中,MVVC(Multi-Version Concurrency Control)工作在RC(Read Commited)和RR(Repeatable Read)这两种隔离级别中。其实MVVC简单理解,就是通过对每个事务赋予一个唯一的、递增的id来代替对数据行上锁从而减小DBMS的开销,也就是读不会加锁。
举个不是很准确的例子,有两个事务T1,T2,它们的id分别是1,2。由于事务id是递增唯一的,因此可以认为T2在逻辑上是后于T1发生的,当T2想要查询(select)某一行,这行的trx_id(最后修改本行数据的事务id)为1,那么我们就可以认为这一行对T2是可见的,因此返回改行数据。
其实这个例子问题很大,这也是为什么要写这篇文章记录一下

前置知识

在InnoDB中,每个行后面都有一些额外的字段,主要要知道DB_TRX_ID(最近修改行的事务ID),DB_ROLL_PTR(指向该行被修改的前一个状态),DELETE_VERSION(行是否被删除)。

当某个事务T对一行R做update操作时,若R对T是可见的(判断方法放在后面讲),将该行的DELETE_VERSION置为T的id,并将改行放入undo log中,而在表中会插入一条新的行R’,R’的DB_TRX_ID为T的id,DELETE_VERSION为空,DB_ROLL_PTR指向刚刚被打入undo log的那行

修改前↓修改前
修改后↓
在这里插入图片描述

READ VIEW

其实ReadView可以理解成数据库中某个时间戳所有未提交事务的快照,ReadView类有这么几个参数:

  • m_ids:当前时间戳所有未提交的事务
  • min_trx_id:m_idx中最小的事务id
  • max_trx_id:当前时间戳InnoDB将在下一次分配的事务id
  • creator_trx_id:当前事务id

当创建一个ReadView对象时,也就知道了这个时间点上未提交事务的所有信息,从而能够通过这些信息实现锁的作用甚至增强。

有了这个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时生成该版本的事务已经被提交,该版本可以被访问。

正题

假如现在DBMS在处理三个事务,T2,T3,T5(T4已经提交了),那么开启下一个事务的时候,将会分配到一个id为6的id,也就是T6。现在T6要select这样一行:

首先会创建一个ReadView对象r:
r.m_ids=[T2,T3,T5],
r.min_trx_id=2,
r.max_trx_id=7
由于该行DB_TRX_ID=2, 而2!<r.min_trx_id,并且T2 in m_ids,因此可以判断出创建快照的时候T2还未提交(当然其实在做这个判断的时间戳上T2也许已经提交了,不过这种CPU调度的事是无法预料的),因此认为这一行对T6是不可见的。

如果该行是这样子的:
由于1<r.min_trx_id=2,因此最后修改该行的事务必然已经提交,所以该行对T6可见。

又如果是:
在这里插入图片描述
那就最后的改动就是在T6中进行的,也是对T6可见。

亦或是这里是引用
CPU调度嘛,人家虽然后来的但也可能先你下手了 。因此由于8>=r.max_trx_id=7,所以该行对T6不可见,找一下DB_ROLL_PTR指向的行,由于是空,返回0行。(如果不为空,那么对所指向的行对同样的可见性判断)

再者:
在这里插入图片描述
虽然r.min_trx.id<=4<r.max_trx_id,但是由于T4 not in m_ids,可知T4已提交,因此该行对T6是可见的。

总结一下就是如下一个流程图:
在这里插入图片描述
copy的,tmin,tmax,tid0分别对应r.min_trx.id,r.max_trx_id,DB_TRX_ID。

回到开头
有些博客写的是
在这里插入图片描述
如果以小于或等于当前事务版本号为依据来判断行的可见性,那么就会漏掉依然活跃未提交的事务,在RR隔离级别下会产生不可重复度(离谱)。

RR和RC的区别

  • READ COMMITTED —— 每次读取数据前都生成一个ReadView
  • REPEATABLE READ —— 在第一次读取数据时生成一个ReadView

Featrue plus

其实在这样的MVVC下,InnoDB在RR隔离级别下就能避免了幻读,原因是不管是后面新的事务还是已经存在的未提交事务,他们新增的数据行对当前事务都是不可见的,而已提交的事务又不可能新增行,妙啊

参考博客:
MVCC ReadView介绍

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值