mvcc机制中的快照读和当前读

什么是MVCC?

MCVV(Multiversion Concurrency Control),多版本并发控制是InnoDB引擎处理读写冲突的手段,目的是用来提高数据库并发场景下的吞吐性能。
不同的事务在并发过程中,SELECT操作可以不加锁,而是通过MVCC机制来指定读取版本,通过一些手段来保证读取的数据符合事务隔离级别,从而解决并发场景下的读写冲突

版本链

又称事务链,每次修改数据的时候,都会记录一条undoLog日志,日志中记录数据每一次的变化,并且通过数据中的两个隐藏列,trx_id(事务id)用标记每一条数据对应的事务id,roll_pointer(指针)用来串联版本链的指针。
在这里插入图片描述

ReadView

阅读视图,可以理解为某一次读取的时候,根据不同的事务生成的数据快照,并且除了表中的数据,还有一下这些固定字段。
m_ids:表示生成ReadView时,当前系统正在活跃的读写事务的事务Id列表。
min_trx_id:表示生成ReadView时,当前系统中活跃的读写事务的最小事务Id。
max_trx_id:表示生成ReadView时,当前时间戳InnoDB将在下一次分配的事务id。
creator_trx_id:当前事务id。

原理

我们都知道,数据库的事务有四个隔离级别:读未提交(Read Uncommitted,简称RU)、读已提交(Read Committed,简称RC)、可重复读(Repeatable Read,简称RR)、串行化(Serializable)。
只有RC和RR才跟MVCC机制有关,因为RU会直接返回记录上的最新值,而Serializable是每一次操作都要加锁。

RC和RR的事务隔离就是通过版本链来控制的,核心逻辑就是判断版本链中的那个版本是当前事务可见可处理的

举个例子,当前有个数据的初始值是 name=“刘德华”

下面是事务时间表,有这样5个事务

时间tx_100tx_200tx_300tx_400tx_500
T1begin;
T2begin;begin;
T3update user set name = “古天乐” where id = 1
T4select * from user where id = 1begin;
T5commit;update user set name = “刘青云” where id = 1
T6select * from user where id = 1select * from user where id = 1begin;
T7commit;
T8select * from user where id = 1select * from user where id = 1

当在T4时间点的时候,版本链如下:

idnametrx_idroll_pointer
1刘德华0null
1古天乐100roll_pointer(指向上一个版本)
RC隔离级别

当在读已提交(Read Committed)隔离级别的时候,每一次读取都会生成一个新的ReadView。

当处于T4时间点,由于tx_100事务未提交,tx_200事务未操作,事务 tx_300 查询出的数据就是 name=“刘德华”。

idnametrx_idroll_pointer
1刘德华0null
1古天乐100roll_pointer(指向上一个版本)

当处于T6时间点,tx_100事务已提交,tx_200事务未提交,那么tx_300事务查询出来的数据就是name=“古天乐”。tx_400事务也是一样。

idnametrx_idroll_pointer
1刘德华0null
1古天乐100roll_pointer(指向上一个版本)
1刘青云200roll_pointer(指向上一个版本)

当处于T8时间点,tx_100、tx_200事务都已提交,所以tx_300、tx_500事务查询到的数据都是name=“刘青云”。

idnametrx_idroll_pointer
1刘德华0null
1古天乐100roll_pointer(指向上一个版本)
1刘青云200roll_pointer(指向上一个版本)

有没有发现一个问题,在tx_300事务中,虽然是同一个事务下,但是每次查询的数据都不一样,这就是出现了不可重复读的现象。

RR隔离级别

当处于可重复读(Repeatable Read)隔离级别的时候,与RC最大的不同就是同一个读取事务,只有一个ReadView。

事务tx_300查询了3次,第一次查询的时候是在T4时间点,tx_100事务还未提交数据,所以生成了一个快照ReadView1,name=“刘德华”。

T6时间点事务tx_300第二次查询的时候不会生成新的快照,依旧获取的是ReadView1,name=“刘德华”。 而此时查询的事务tx_400,则会生成快照ReadView2,name=“古天乐”。

T8时间点的时候,事务tx_300第三次查询依旧不会生成新的快照,获取的数据还是ReadView1,name=“刘德华”。 此时查询事务tx_500,则会生成新的快照ReadView3,name=“刘青云”。

MVCC机制,就是通过版本链来控制每一个事务读取的版本,从而实现事务的隔离级别。关键是要理解,如何通过控制ReadView的生成,来实现不同的事务隔离级别。

当前读

读取的是最新版本,并且对数据加锁,阻塞其他操作修改记录。
比如select… update,update,delete,insert这类操作都是当前读

快照读

只有select单纯的读取操作,会在读取的时候生成ReadView快照数据。
并且RC隔离级别下,会在每次select操作的时候都生成一个ReadView快照。
而在RR隔离级别下,同一个事务中只会在第一次select操作的时候生成ReadView快照,避免同一个事务多次读取的数据不一样。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木小同

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值