大家好 我是积极向上的湘锅锅
顾名思义,读取的就是当前最新的版本,而且读取的时候保证其他并发事务不会修改该记录,会对记录加锁(共享锁或者是排它锁),如:select … lock in share mode(共享锁),select …
for update、update、insert、delete(排他锁)都是一种当前读
简单的 select(不加锁)就是快照读,快照读读取的可能是最新版本,也有可能是历史数据
Read Committed:每个select都会产生一个快照读
Repeatable Read:开启事务后第一个select才是快照读的地方
Serializable:快照读会退化为当前读(加锁)
全称Multi-Version Concurrency Control,多版本并发控制,指维护一个数据的多个版本,使得读写操作没有冲突,也就是不会产生读写锁冲突,而快照读为MySQL实现MVCC提供了一个非阻塞读功能,这给我们高并发性能提升不少
MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView
接下来,我们再来介绍一下InnoDB引擎的表中涉及到的隐藏字段 、undolog 以及 readview,从
而来介绍一下MVCC的原理。
举个例子当我们创建了这张表,在查看表结构的时候,只看得到这三个显示的字段,但是实际上除了这三个字段意外,InnoDB还会自动的给我们添加三个隐藏字段,如下:
而上面前俩个字段是肯定添加的,而第三个要看是否自己设置了主键,如果没有指定主键,则会添加该字段
回滚日志,在insert,update,delete的时候产生便于数据回滚的日志
为什么叫版本链,慢慢往下看…
DB_TRX_ID : 代表最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID,是自增的
DB_ROLL_PTR : 指向上一个版本,由于这条数据是才插入的,没有被更新过,所以该字段值为null。
然后,有四个并发事务同时在访问这张表
当事务2开始修改数据时,会产生undo log日志,记录数据变更之前的样子,并且会记录本次操作的事务id
当事务3执行第一条修改语句时,也会记录记录undo log日志,记录数据变更之前的样子,然后更新版本记录,并且记录本次操作事务id
当事务4执行第一条修改语句时,也会记录undo log日志,记录数据变更之前的样子; 然后更新记
录,并且记录本次操作的事务ID
最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条
记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录
Readview(读视图)是快照读SQL执行的时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id
Redaview中包含了四个核心字段:
看图有点抽象,我觉得可以这样理解
而在readview中就规定了版本链数据的访问规则:
trx_id 代表当前undolog版本链对应事务ID
看这可能有的小伙伴有点懵 我对这张图解释一下,不对之处请指出
不同的隔离级别,生成ReadView的时机不同
RC隔离级别下,在事务中每一次执行快照读时生成ReadView。
我们就来分析事务5中,两次快照读读取数据,是如何获取数据的?
在事务5中,查询了两次id为30的记录,由于隔离级别为Read Committed,所以每一次进行快照读
都会生成一个ReadView,那么两次生成的ReadView如下:
这里有图也可以好好理解一下ReadView每一个字段所代表的具体含义
那么俩次快照读在获取数据的时候,就需要根据所生成的ReadView和ReadView的版本链访问规则,到undo log版本练中匹配数据,最终决定此次快照读使用哪一条记录的数据
A.先来看第一次快照读具体的读取过程
下图是版本链和访问规则
在进行匹配时,会从undo log的版本链,从上到下进行挨个匹配:
先匹配这条记录
这条记录对应的trx_id为4,也就是将4带入右侧的匹配规则中
①不满足 ②不满足 ③不满足 ④也不满足 ,
都不满足,则继续匹配undo log版本链的下一条
再匹配第二条
这条记录对应的trx_id为3,也就是将3带入右侧的匹配规则中。
①不满足 ②不满足 ③不满足 ④也不满足
都不满足,则继续匹配undo log版本链的下一条
再匹配第三条
这条记录对应的trx_id为2,也就是将2带入右侧的匹配规则中。
①不满足 ②满足
终止匹配
此次快照读,返回的数据就是版本链中trx_id为2记录的这条数据
B. 再来看第二次快照读具体的读取过程
上图中注意第二次快照读是下面那个ReadView
先匹配这条记录
这条记录对应的trx_id为4,也就是将4带入右侧的匹配规则中
①不满足 ②不满足 ③不满足 ④也不满足
都不满足,则继续匹配undo log版本链的下一条
再匹配第二条
这条记录对应的trx_id为3,也就是将3带入右侧的匹配规则中。
①不满足 ②满足
终止匹配
此次快照读,返回的数据就是版本链中记录的这条数据
RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。 而RR 是可
重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的
那在MVCC的机制下,是如何防止可重复读的呢?
还是用事务5举例
我们看到,在RR隔离级别下,只是在事务中第一次快照读时生成ReadView,后续都是复用该
ReadView,那么既然ReadView都一样, ReadView的版本链匹配规则也一样, 那么最终快照读返
回的结果也是一样的
所以呢,MVCC的实现原理就是通过 InnoDB表的隐藏字段、UndoLog 版本链、ReadView来实现的,而MVCC + 锁(next-key ),则实现了事务的隔离性。 而一致性则是由redolog 与 undolog保证