MySQL-MVCC

什么是MVCC?

Multi-Version Concurrency Control 多版本并发控制,是一种基于无锁思想的并发控制方法
MVCC维持一个数据的多个版本,使得读写操作没有冲突
MVCC通过快照读,可以在可重复读隔离级别下解决幻读。因为每次读当前快照,表中数据行数发生变化也不会受到影响。

MVCC 只在读已提交可重复读两个隔离级别下工作。
其他两个隔离级别都和MVCC不兼容:
因为读未提交总是读取最新的数据行,而不是符合当前事务版本的数据行,所以不需要MVCC
而 串行化则会对所有读取的行都加锁,也不需要MVCC

当前读和快照读

什么是快照读?
事务在执行读取操作时会生成一个快照,之后即使其他的事务修改了表中的数据,读取操作仍然读取这个快照,而不是去读取最新的数据。因此实现了可重复读和幻读
什么是当前读?
当前读就是读取当前数据库中最新的数据内容

什么情况下是快照读?
所有普通的SELECT语句在读已提交和可重复读隔离级别下都算是快照读。
什么情况下是当前读?
除了上面的普通select,其他都是当前读,例如:select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)等这些操作都是当前读

快照是什么时候生成的呢?
事务启动之后,第一次执行select时生成

MVCC的实现原理

快照

快照是什么
在该事务执行快照读的那一刻,会生成数据库系统当前的一个快照,快照里记录系统当前活跃事务的ID(活跃事务是指已启动但未提交的事务,事务ID是事务的唯一标识,是按申请顺序严格递增的)。

快照的作用?
快照主要是用来做可见性判断的,判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的之前某个版本的数据。

快照工作原理:
因为每行数据都有多个版本。每次事务更新数据的时候,都会生成一个新的版本,旧的数据版本也要保留(利用undo log保留旧版本)

下图就是一个记录被多个事务连续更新后的状态。
>

因此,一个事务只需要在启动的时候声明说:
以我启动的时刻为准,如果一个数据版本是在我启动之前生成的,就认;
如果是我启动以后才生成的,我就不认,我必须要找到它的上一个版本。如果上一个版本也不可见,那就得继续往前找,直到直到我启动之前就生成好的版本。
当然,如果是我自己更新的数据,我还是要认的。

上面的这些功能是怎么实现的呢?

InnoDB 为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在活跃的所有事务 ID
数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位

而数据版本的可见性规则,就是基于低水位和高水位来划分的,如下图:
在这里插入图片描述
这样,对于当前事务的启动瞬间来说,一个数据版本的事务ID,有以下几种可能:

  1. 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
  2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
  3. 如果落在黄色部分,那就包括两种情况
    a. 若 事务ID 在数组中,表示这个版本是由还没提交的事务生成的,不可见
    b. 若 事务ID不在数组中,表示这个版本是已经提交了的事务生成的,可见

总结:
对于一个快照来说,事务它够读到哪些版本数据,要遵循以下规则:
当前事务内的更新,可以读到;
版本未提交,不能读到;
版本已提交,但是却在快照创建后提交的,不能读到;
版本已提交,且是在快照创建前提交的,可以读到;

undo log链表

每次记录更新前,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被连接成一个链表,我们把这个链表称之为版本链
如下图
在这里插入图片描述
如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

读已提交和可重复读的原理区别

二者的本质区别就是它们生成快照的时机不同
可重复读是只在事务开始的时候,生成一个当前事务全局性的快照,即只生成一次。重复读到的数据都是这个快照的,所以可重复读。
读已提交则是每次执行语句的时候都重新生成一次快照,每次生成都会把之前的记录丢掉,所以无法重复读。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值