Mysql之MVCC机制

前面已经讲述了Mysql Innodb存储引擎下的事务隔离级别与锁机制,我们知道了
Mysql的四种隔离级别,其中最常用的是可重复读(Repeatable Read)读已提交(Read Committed) . RR相比较RC,解决了不可重复读问题,而RC每次都能读到数据行最新的数据. 他们的底层则是通过MVCC机制实现的.

MVCC机制

MVCC即多版本的并发控制(Multi-Version Concurrency Control).它主要通过undo日志版本链和 ReadView一致性试图实现.

undo日志版本链

// 插入数据
insert into student(id, name, age) VALUES (1,'鸣人',16);
// 则生成如下undo日志版本
undo日志版本链包含 trx_id(事务id)roll_point(指针)

在这里插入图片描述

// 后续有其他事务对该记录进行更新
// 事务200
update student set name = '佐助' where id = 1;
// 事务300
update student set name = '我爱罗' where id = 1;
// 事务400
update student set name = '宁次' where id = 1;
// 每次操作同一行数据都会生成对应的一个undo日志,通过roll_pointer把这些日志记录连接起来,形成一个历史记录版本链。如下图:
黄色代表历史undo日志,蓝色代表最新的undo日志

在这里插入图片描述

// undo日志版本链的删除
1.当是insert操作的时候,当事务提交则可以删除undo日志版本链了.
2.当是update操作的时候,当事务提交后不会立刻删除undo日志版本链,需要确定该行数据已经没有被其他事务关联了,才会删除.

ReadView

一致性视图是一个时间点的快照,用于决定事务在读取数据时能够看到哪些数据版本.

// 视图组成
m_ids:生成ReadView时,当前系统的活跃事务id集合
min_trx_id:生成ReadView,活跃事务id最小值(m_ids的最小值)
max_trx_id:生成ReadView,系统分配的下一个事务id值
creator_trx_id:生成ReadView,当前事务的id

// 举例以上图undo日志版本链为例,按下图时间轴执行顺序

在这里插入图片描述
生成的ReadView为下图
在这里插入图片描述

版本链对比规则

// 对比规则
1.如果访问版本的trx_id值与ReadView的creator_trx_id值相同,则表示访问自己事务中修改的记录,所以可以访问。
2.如果访问版本的trx_id值小于min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以可以访问.
3.如果访问版本的trx_id值大于或等于max_trx_id值,表明生成该版本的事务在当前事务生成ReadView前还没有提交,所以不可以访问.
4.如果访问版本的trx_id值在min_trx_id与max_trx_id值之间,则需要判断trx_id值是否在m_ids中,如果在说明生成ReadView时是活跃事务,所以不可以访问.
如果不在说明生成ReadView时不是活跃事务(表明已提交),所以可以访问.

实践说明

根据下图时间轴操作,我们主要关注:

  1. trx_id = 400 在时间轴4,8返回的值
  2. trx_id=500在时间轴7,9返回的值
    在这里插入图片描述

日志版本链

根据上图id=1的记录的undo日志版本链为下图:
在这里插入图片描述

ReadView

ReadView是在第一次执行select查询语句的时候生成的

// 以trx_id = 400为视角,生成的ReadView为
m_ids:[200,300,400500]
min_trx_id:200
max_trx_id:501
creator_trx_id:400
// 以trx_id = 500为视角,生成的ReadView为
m_ids:[300,400500]
min_trx_id:200
max_trx_id:501
creator_trx_id:500

查找数据

// 以trx_id = 400为例
// 当处于时间轴4的时候
此时undo版本链只有初始第一次数据,所以从这条数据开始查找,该条数据的trx_id =100,根据比较规则,小于当前min_trx_id(即100<200),所以该条数据是可见的,所以数据肯定是name='鸣人';
// 当处于时间轴8时
此时undo版本链已经有上图全部数据行里,所以从最新数据开始查找
1.从trx_id = 300开始比较,300在m_ids集合中,视图生成时是活跃事务,所以不可见;
2.继续往上看trx_id=200,也在m_ids中,所以不可见;
3.最终来到trx_id=100,可见;所以最终结果还是name='鸣人';
// 以trx_id = 500为例
// 当处于时间轴7的时候
此时undo版本链已经有上图全部数据行里,所以从最新数据开始查找
1.从trx_id = 300开始比较,300在m_ids集合中,视图生成时是活跃事务,所以不可见;
2. 继续往上看trx_id=200,不在m_ids中,所以可见;最终结果name='我爱罗'

// 当处于时间轴9的时候
如果是RR级别,ReadView不变,所以结果还是name='我爱罗';
如果是RC级别,每次都会重新生成ReadView
				m_ids:[500]
				min_trx_id:500
				max_trx_id:501
				creator_trx_id:500
根据规则可以知道:最终结果为name='宁次';
MySQLMVCC(多版本并发控制)机制是保证数据一致性的重要手段。MVCC的核心思想是在数据库中保存多个版本的同一行数据,这些版本在不同的时间被不同的事务读取和修改。因此,每个事务看到的数据版本都是不同的,以此来提高并发性和隔离性。 在MySQL中实现MVCC需要以下两个机制: 1. 版本号:每个数据行都有一个版本号,用来标识该行的版本信息。版本号是一个递增的数字,每次更新数据时都会增加。 2. 快照读:在MVCC中,读取数据时不会对其进行加锁,而是通过快照读的方式来读取数据。快照读会读取最近的数据版本,如果该版本已经被其他事务修改,则会读取最近的未被修改的版本。 当一个事务读取数据时,MySQL会将当前事务的版本号和数据行的版本号进行比较,如果当前事务的版本号小于数据行的版本号,则说明当前事务读取的数据已经被其他事务修改了,此时MySQL会重新读取最新的数据版本。这样可以避免脏读和不可重复读等问题。 当一个事务更新数据时,MySQL会将数据行的版本号加1,并将新版本的数据插入到数据库中。同时,MySQL会将旧版本的数据标记为已经删除,但是并不会真正删除,这样可以保证其他事务仍然可以读取旧版本的数据。 总之,MVCC机制通过版本号和快照读的方式来保证事务的隔离性,避免了脏读、不可重复读和幻读等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值