一篇文章彻底搞懂MySql之MVCC机制



前言

最近在梳理自己的知识点,发现MVCC这一块理解不太深刻,去网站上查询了下,也没看到容易理解的,所以有了这篇文章,通过模拟多个事务执行,清晰的可以看见每一步执行步骤,可以清晰的对MVCC有个深刻认识。


什么是MVCC?

Mysql在可重复读这个隔离性就是靠MVCC(Multi-Version Concurrency Control)机制来保证的,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥;

而在串行化隔离级别为了保证较高的隔离性是通过将所有操作加锁互斥来实现的。

Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。


一、undo日志版本链

undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个**隐藏字段trx_id(事务ID)和roll_pointer(指针)**把这些undo日志,串联起来形成一个历史记录版本链;

PS:
事务id trx_id:挨个递增生成,图上是为了显目一点随便写的
指针roll_pointer :指向老数据,同一个数据,多次处理,每次处理的回滚日志的指针都会指向老的那个日志

简单理解就是undo日志版本链其实就是undo回滚日志的集合。


下图是一个undo日志版本链案例

案例解析
在这里插入图片描述
mysql依次开启了3个事务,有3个不同的事务id编号(这里的3条sql操作没有关系,不用在意)
并且后面还有一个查询sql(划重点)

这个sql会创建一个read VIew 一致性视图


二、read-view一致性视图

可重复读隔离级别,当事务开启、执行任何查询sql时会生成当前事务的一致性视图read-view

该视图在事务结束之前都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成);


2.1、read-view视图的组成

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

结合上面的图来理解如何组成:
上面3个update,2个事务未提交,紧跟着在进行一个select,然后就生成了一致性视图
事务ID100和200 组成 未提交的id数组,已经提交的事务id是300
数组里最小的是100,所以min_id是100,max_id是300

可能会有个疑问

这时候查询上面那个account表 他的结果是lilei300
为什么是lilei300 ,其实是内部有一个undo版本链的比对规则,带着这个疑问往下看


下图来个案例解析

下图可以看见有一张account表,每一行字段有id和name,隐藏字段trx_id(事务ID)和roll_pointer(指针,指向修改前的那一条数据);

在这里插入图片描述


三、undo版本链比对机制

通过上面得知:
事务数组里最小的是100,所以min_id是100,max_id是300

mysql会根据undo版本链生成3个区间用于比对
绿色
已经提交事务
小于100的不出意外都是已经提交事务

黄色
未提交和已经提交的事务
最小的是100,后面的事务由于是挨个依次递增,所以这里面都是 未提交和已经提交的事务

PS:但是注意,这里有一种可能 也存在小于100的在这个区间
比如在100之前,有一个事务id 80的开启了事务并且很快就commit了,也可能在黄色区间你

红色
未开始的事务
因为最大的是max_id是300,所以大于300的 肯定都是未开始的事务


版本链比对规则:

1、 如果 row 的 trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的

2、 如果 row 的 trx_id 落在红色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的是不可见的(若 row 的 trx_id 就是当前自己的事务是可见的);

3、如果 row 的 trx_id 落在黄色部分(未提交 和 已经提交事务)(min_id <=trx_id<= max_id),那就包括两种情况

a. 若 row 的 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的不可见
(若 row 的 trx_id 就是当前自己的事务是可见的);

b. 若 row 的 trx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见

trx_id代表当前事务id
所以基于此,上面的事务id 300,所以他在黄色区间,他命中了上面 b 规则,
所以后面的查询,结果是lilei300

ps:

对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,

然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,

在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

注意:begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个修改操作InnoDB表的语句,事务才真正启动,才会向mysql申请事务id,mysql内部是严格按照事务的启动顺序来分配事务id的。


三、MVCC获取值流程(全流程重新梳理一遍)

3.1、阶段1

如下图transaction100、transaction200都未提交(这2个就是未提交的事务id数组),加上transaction300已经提交的事务(最大事务id)组成;
在#select1执行查询时就会生成read-view视图;

readview包含的实际值:[100,200], 300

在这里插入图片描述

这里数组最小的100,也就是min_id,最大的ID,300为max_id;
下图有3个分区,mysql根据版本比对规则去匹配,拿到最终的快照;
在这里插入图片描述

执行下面sql,结果返回的是lilei300?为什么?

select name from account where id = 1

拿上面的sql案例解析
这里时候查询到的数据事务id是300,所以满足上面第3种情况,min_id <=trx_id<= max_id,300是最大事务id,他不在未提交的事务数组内,所以3:a不满足,所以他满足了3:b,表示已经提交了事务,是可见的,所以上面的sql查询结果是lilei300。


3.2、阶段2

然后接着上面的案例继续往下执行,这时候Transaction100继续执行2条uapdate,然后select1继续查询同一个sql。
然后拿到了之前的那个一致性视图,然后从版本里最新的一条数据去取,发现现在最新一条数据事务ID为100,然后去比对。
在这里插入图片描述
在这里插入图片描述
执行顺序
1、他会先找到最后update的那一条数据(lilei2,他的事务id是100,),然后按照规则去比对,事务100他是未提交的事务,所以也是落在黄色区域,然后他满足3:a,因为他在事务数组中,所以他是不可见。

2、然后就会往上找(找到lilei1),然后发现他也是落在黄色区域并且也是在数组内,所以满足3:a所以也是不可见。

3、在往上找(找到lilei300),事务id是300,不在数组内,可见,mvcc到此结束。


3.3、阶段3

这里先把Transaction100事务提交,并且transaction200执行了2条update,最后select1再次进行查询。
然后拿到了之前的那个一致性视图,然后从版本里最新的一条数据去取,发现现在最新一条数据事务ID为200,然后去比对。

在这里插入图片描述
执行顺序
其实和上面阶段2一样,因为可重复读的一致性视图,没有变,所以事务200,依然属于未提交数组内,所以往上找,找到事务100,还是不可见,直到找到事务300,可见,结束。

在这里插入图片描述


总结

undo日志版本链(回滚日志的集合);
read-view一致性视图,包含未提交事务的id和最大id;

比对规则用于查找可见的数据;

MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。

这也就是为什么一个事务里查询,每次查询结果是一样的最终原因

MySQLMVCC(Multi-Version Concurrency Control)机制是一种并发控制机制,用于处理并发事务的读写冲突。它通过为每个事务创建一个独立的版本,并使用这些版本来提供对数据的一致性读取,从而实现并发控制。 MVCC机制MySQL中的实现主要依赖于以下两个重要的组件: 1. Undo日志:MySQL使用undo日志记录数据修改操作的旧值。当一个事务开始时,MySQL会将当前数据行的快照复制到undo日志中。如果其他事务需要读取该数据行,它将读取这个快照而不受正在进行的事务的影响。 2. Read View:Read View是一个事务的快照视图,用于确定哪些数据行是对当前事务可见的。每个事务在开始时都会创建一个Read View。Read View包含一个活动事务列表和一个已提交事务列表。活动事务列表包含当前正在运行的活动事务,已提交事务列表包含已经提交的事务。当一个事务需要读取数据时,它会根据Read View确定哪些数据行是可见的。 基于这两个组件,MVCC机制提供了以下几个特点: 1. 高并发性:MVCC机制允许多个事务并发地读取和修改数据,因为它们之间不会产生读写冲突。 2. 一致性读取:MVCC机制确保事务只能读取已经提交的数据,避免了脏读和不可重复读的问题。 3. 无锁读取:MVCC机制的读取操作不会阻塞写入操作。读取操作只需要根据Read View判断数据是否可见。 需要注意的是,MVCC机制只适用于InnoDB存储引擎,而不适用于其他存储引擎,如MyISAM。另外,MVCC机制在一些特殊情况下可能会导致存储空间的增加,因为每个事务都会创建一个版本。因此,在设计数据库时需要考虑这些因素。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

未闻花名丶丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值