MVCC处理可重复读理解

前言:通过上节我们知道Mysql将事务设置为可重复读隔离级别后可以避免数据脏读和不可重复读问题。那么可重复读具体是怎样实现的呢?MVCC是个啥?可以接着往下看。

我们先看一下定义(维基百科):

  • 多版本并发控制(Multiversion concurrency control, MCC 或 MVCC),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存。
  • MVCC意图解决读写锁造成的多个、长时间的读操作饿死写操作问题。每个事务读到的数据项都是一个历史快照(snapshot)并依赖于实现的隔离级别。写操作不覆盖已有数据项,而是创建一个新的版本,直至所在操作提交时才变为可见。快照隔离使得事物看到它启动时的数据状态。

大概意思是,在Mysql中,我们修改数据时并不是直接将旧数据抹除,而是将新数据“盖在”旧数据上面,这样处理对于修改数据前已经查询过数据的用户是没有影响的,还是可以查看到历史版本的数据,从而实现可重复读。

在这里插入图片描述

  1. 阿雷每天上班的路上新开了一块空地准备建写字楼。
  2. 第一天经过时才只盖了一层,出于好奇心,阿楼爬上了一楼,打算去看下是个什么情况,谁知道把手机落在了那里(好奇心害猫go die)。
  3. 隔一段时间后,突然回忆起有去过这么个地方,手机可能就在那里,于是阿雷就赶紧跑过去查看,不过这个时候房子已经盖到六层了。
  4. 可是阿雷知道即使房子已经建到六层,但我还是要去一楼找,并且还顺利找到了手机。

修改数据就好比盖房子,一层一层往上累计。那在Mysql里面是怎样建这层楼的呢?我们先看个图:
在这里插入图片描述

在数据库中有一张language表,里面有两个字段【id】和【name】,其中trx_id和roll_pointer分别表示当前记录操作的事务id和指向旧数据的指针。

最开始新增了一条【name = java】的数据,后来修改成为【name = c++】。后续修改操作依此类推,这样就楼房就一层层往上盖。而实际这栋楼叫做【undo日志版本链】。

那如果其他事务对当前记录进行select操作,怎样保证数据的修改不会影响到其他事务呢?就像阿雷知道即使楼层变了,但我也知道去一楼找手机,而不是去其他楼层呢?

Mysql使用一致性视图read view机制去实现这一逻辑。在可重复读隔离机制下,当我们在事务中执行任何查询sql时,就会生成一致性视图(注意不是begin时就生成视图,而是在执行第一条sql语句时生成),直到事务结束。(读已提交隔离机制是每次查询sql,都会重新生成视图,这也是为什么提交修改的数据后,其他事务可以马上读取到的原因)。

read view保存了执行查询时所有未提交事务id数组(数组里最小的id为min
_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。

对比规则:

  • trx_id < min_id ,表示trx_id事务已提交,数据可见。
  • trx_id > max_id ,表示trx_id事务未发生,数据不可见面。
  • min_id <= trx_id <= max_id
    1. trx_id在视图数组里面,则表示trx_id还未提交,数据不可见(如果当前事务就是自已的,则是可见)。
    2. trx_id不在视图数组里,则表示trx_id已提交,数据可见。

当在新增完【name = java】记录,我们查询数据,这时min_id为空,max_id=100,从上往下索引查询,300>100,200>100,则都是不可见,100不在视图数组里面,所以即使我们后续在进行修改操作,在这个事务里面,我们查询的数据依旧是【name = java】

总结:通过本节我们可以知道Mysql通过undo日志版本链和一致性视图来实现MVCC机制,从而实现数据可重复读。阿雷最开始觉得一致性视图的实现是比较绕的,但是只要一想到查询数据前后是不会变的,然后再去推导过程就会豁然开朗。我是阿雷,学无尽,无尽学。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值