您现在的位置是:首页 > 编程 > 

MySQL进阶突击系列(05)突击MVCC核心原理

2025-07-26 08:50:47
MySQL进阶突击系列(05)突击MVCC核心原理 2024小结:在写作分享上,特别感谢腾讯云开发者社区每个月都有相关分享交流活动,支持大家持续学习分享交流,共同进步。社区诚意满满的干货,让大家收获满满。对我而言,珍惜每一篇投稿分享,每一篇内容字数大概6000字左右,加上画图,以及案例demo代码编写、实战,撰稿时长平均小时左右。由于年底工作特别忙,晚上下班回家,有时候娃已经睡着了,如果娃没睡还

MySQL进阶突击系列(05)突击MVCC核心原理

2024小结:在写作分享上,特别感谢腾讯云开发者社区每个月都有相关分享交流活动,支持大家持续学习分享交流,共同进步。社区诚意满满的干货,让大家收获满满。

对我而言,珍惜每一篇投稿分享,每一篇内容字数大概6000字左右,加上画图,以及案例demo代码编写、实战,撰稿时长平均小时左右。由于年底工作特别忙,晚上下班回家,有时候娃已经睡着了,如果娃没睡还得陪娃玩直到她睡着才有空继续写作。每天空闲时间非常少,经常一篇文章从周一写到周末才能完成。

近5个月以来投稿并不多,仅29篇。好在其中有10篇得到平台认可并获得首页推荐,最终全年得到作者热度89的排名,2014是收获的一年。感恩感谢!新的一年,争取有更多时间,和大家交流学习分享,包括家庭、日常、职场其他非技术性内容。


一、前言背景

二、通俗演义-MVCC多版本并发控制核心原理

2.1 解密-基于undoLog实现的数据版本链

2.2 弯弯绕绕看不懂的readView视图-一句话总结看懂

三、MVCC解决脏读、不可重复读、幻读问题demo详解

.1 验证MVCC解决脏读、不可重复读问题【并发事务一个重复查+另一个改】

.2 验证MVCC解决幻读、不可重复读问题【并发事务一个重复查,一个新增】

四、脏写是什么?如何解决


期待可以写一篇2024总结,聊聊日常生活、职场等非技术内容。

一、前言背景

之前系列4文章说过,MySQL InnoDB存储引擎,默认事务隔离级别是可重复读repeatable-read。我们可通过命令查看:SELECT @@_isolation;

而且也说到,MySQL的可重复读事务隔离级别,可以解决脏读、幻读、不可重复读三大事务并发问题。当时也留了一个思考题:MySQL是如何做到的?答案是MVCC+锁。核心在于MVCC。

那MySQL如何让实现一个事务多次读,不受另一个事务的增、改、删的影响。带着这个问题,我们一步步解密MySQL的MVCC多版本并发控制核心机制。

二、通俗演义-MVCC多版本并发控制核心原理

MVCC,全称是Multi Version Concurrency Control多版本并发控制。MySQL innoDB存储引擎,在新增修改删除数据的时候,并没有真正用新数据直接更新覆盖,而是采用版本链方式去保存数据修改记录。每个读事务,对应一个版本的数据快照。每个写事务,在事务提交之前,该事务内做的任何更新操作未提交之前,其他任何事务不可见该更新。

举一个通俗的案例,也是我们日常实践的数据版本管理。比如用户信息user (id,name,age,city,cs_level)修改,我们不会简单的直接进行update,通常会进行数据历史记录。比如最简单的user表增加一个is_valid字段,利用主键id自增的特性,把它当做用户信息更新版本号。每次更新用户信息,将原信息is_valid置为false。然后用新信息去构建一条is_valid=true数据。这样就可以完成版本记录追溯。

MVCC的数据快照、数据版本链就是是类似效果。但是在并发事务里读写,具体原理会复杂很多。

2.1 解密-基于undoLog实现的数据版本链

在MySQL表里,有2个隐藏的字段,一个是事务的ID:trx_id,这个事务id就是最近一次更新该数据的事务id;另一个是回滚指针:roll_pointer ,该指针指向的就是更新该数据之前的undoLog,可以通俗理解为:修改前数据。据此,隐藏的事务id,和回滚指针的意义,一目了然,一个表示哪个事务更新了该数据,一个表示该数据更新前的样子。

比如下图:事务trx_id=98的操作,新增了name=【拉丁解牛说技术】的这行数据。新增数据的时候,roll_pointer是空。此后,事务99对该数据进行修改,把name改为=【老牛】。此时如下图,回滚指针指向老版本事务98的数据。这样数据版本链清晰可见。

另外说一下,在MVCC里只有更新、删除、新增操作有让事务ID新增,查询是不会让数据事务发生变化。

2.2 弯弯绕绕看不懂的readView视图-一句话总结看懂

readview顾名思义是读视图,当开启一个事务,MySQL会根据当前事务隔离级别,给你这个事务开启独立的review视图空间。这里很多博文在讲解readview机制时候,会对当前最大max_trx_id最小,min_trx_id,当前事务this_trx_id,视图开启时候活跃的事务id组等多个事务id进行比较说明,讲的非常细。不过这里的判断规则说这么细,如果读者些微没跟上,或者失去耐心,可能就错失理解掌握readview的核心机制。

我们坚持大道至简的方法,总结readview视图核心机制,最直接一句话:每个事务只能读到对应事务隔离级别的数据。

我们简单举例说一下:

如下图,当前事务隔离级别是可重复读RP,并发事务100要重复多次查询,事务101 要更新name为【zhangsan】。事务并发开始前如下:

接下来具体操作:

1、事务id=100进行查询,首先查到了事务99的数据,发现自己的事务ID100比99大,直接返回读到该数据【老牛】。

2、接下来事务id=101,把数据更新为【zhangsan】并提交更新trx_id=101,回滚指针指向了之前trx_id=99的老数据。

、事务100,继续重复读,这时候读到了trx_id=101的最新数据,发现比自己的trx_id=100还大。在当前每个事务只能读到对应事务隔离级别的数据原则下,而且当前事务隔离级别是可重复读RP。按规则,不好意思,这个101事务修改的数据我不能读,得继续遍历undoLog版本链,到了下一个事务id=99的数据【老牛】,发现99< 100,非常好,符合事务隔离级别要求。那这次重复读,读的还是之前的数据【老牛】。

同样道理,如果是事务隔离级别在读已提交、读未提交,判断规则也只是对应判断当前自己的事务ID与读到的数据事务id大小关系是否满足事务隔离级别即可。

当然,这里核心再详细展开确实有很多细节,比如读已提交隔离级别下,每次查询,就是开启一个新的readview。这个和可重复读隔离级别不一样。

理解了MVCC核心原理,我们设计场景,在InnoDB默认的事务隔离级别「可重复读RP」下,一步步实践验证解决脏读、幻读、不可重复读问题。

三、MVCC解决脏读、不可重复读、幻读问题demo详解

新建一个user_mvcc_demo表,多个事务并发读、修改name值、以及新增写入,来具体验证mvcc核心机制。

代码语言:txt复制
CREATE TABLE user_mvcc_demo (
    `id` int(11) OT ULL AUTO_ICREMET,
    `name` varchar(16) DEFAULT ULL,
    PRIMARY KEY (`id`)
    ) EGIE=InnoDB AUTO_ICREMET=1 DEFAULT CHARSET=utf8;
-- 新增一条数据,id=1
insert into user_mvcc_demo(name)values ('拉丁解牛说技术001');

.1 验证MVCC解决脏读、不可重复读问题【并发事务一个重复查+另一个改】

之前说过:脏读,特指的就是一个事务里select查询到另一个事务update语句未提交的脏数据场景。

本demo模拟场景:事务1里面多次重复查询id=1的name值,而事务2并发修改了name值并提交。

预期结果:在事务1里每次查询都是数据快照‘拉丁解牛说技术001’;事务2提交事务前、后,事务1均读不到name的新值zhangsan。

具体如下:

事务1 SQL:

begin;

select * from user_mvcc_demo where id=1;

select now();-- 时间 2025-01-0 16:04:46

select * from user_mvcc_demo where id=1;

多次查询

.....

事务2 SQL:

begin;

select * from user_mvcc_demo where id=1;

select now();-- 时间 2025-01-0 16:04:46

update user_mvcc_demo set='zhangsan' where id=1;-- 更新name 为zhangsan

select * from user_mvcc_demo where id=1;

select * from user_mvcc_demo where id=1;--- 此时未提交,但事务1读不到脏数据zhangsan

commit;--提交后,事务1仍然读不到新快照数据zhangsan

.....

实践结果:

在事务1内,多次查结果都是:拉丁解牛说技术001。实际上,在另一个事务2, 时间 2025-01-0 16:04:26 已经修改name为zhangsan。

且事务2提交事务后,在事务1里,继续多次查询,查到的也是事务1开启事务后,对应的快照数据:拉丁解牛说技术001,验证MVCC解决脏读、不看重复读问题完成。

如下图两个会话:

.2 验证MVCC解决幻读、不可重复读问题【并发事务一个重复查,一个新增】

系列具体说过,不可重复读问题:一个事务读到了另一个事务已提交的数据。主要针对的是一个事务里select到另一个事务update或者delete语句的更新结果。

而幻读:一个事务读到另一个事务新增的数据,特指一个事务里select查询查到了另一个事务insert数据。

本demo模拟场景:事务1里面多次重复查询全表,而事务2新增了一条数据并提交。

预期结果:在事务1里每次查询都只有一条数据;事务2提交事务前、后,事务1均读不到新增那条数据。

仍然是user_mvcc_demo表,里面只有一条id=1,name=‘zhangsan’;的数据。

事务1:重复读select * from user_mvcc_demo 。

事务2:新增1条数据。insert into user_mvcc_demo(name)values('拉丁解牛说技术');

具体如下:

事务1 SQL:

begin;

select * from user_mvcc_demo;

select now();-- 时间 2025-01-0 16:40:45

select * from user_mvcc_demo;

多次查询

.....

事务2 SQL:

begin;

select * from user_mvcc_demo;

select now();-- 时间 2025-01-0 16:40:22

insert into user_mvcc_demo(name)values('拉丁解牛说技术');;-- 新增了一条'拉丁解牛说技术'的数据

select * from user_mvcc_demo;

commit;--提交后,事务1仍然读不到新快照数据'拉丁解牛说技术'

.....

实践结果,与预期一致:在事务1里每次查询都只有一条数据zhangsan;而事务2提交事务前、后,事务1均读不到新增那条数据'拉丁解牛说技术'。

四、脏写是什么?如何解决

脏读,说过很多次,脏写大家听的很少。所谓脏写:就是并发事务更新同一个数据,比如2个并发事务修改id=1,的name值,之前name值是【拉丁解牛说技术】。事务1此时想改成zhansan并提交,而事务2改成lisi,但是中途回滚了,回滚为老数据【拉丁解牛说技术】。对于事务1来说,这就是脏写问题。

MySQL是通过锁机制来保障并发事务串行化执行,避免事务并发脏写问题。简单的说,更新事务读到数据后,需要先加锁,加锁成功才能开始执行更新事务。未拿到锁的事务,需要等待锁。这个和Java并发编程的锁机制类似。

篇幅有限,具体锁相关类型、以及具体场景锁分析,我们下一篇继续分享。

推荐阅读拉丁解牛相关专题系列(欢迎交流讨论搜:拉丁解牛说技术):

1、JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC

2、JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?

、JVM进阶调优系列()堆内存的对象什么时候被回收?

4、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

5、JVM进阶调优系列(1)类加载器原理一文讲透

6、JAVA并发编程系列(1)Future、FutureTask异步小王子

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1190486.html

相关标签:无
上传时间: 2025-07-22 20:38:35
留言与评论(共有 20 条评论)
本站网友 深圳地税
24分钟前 发表
删的影响
本站网友 合肥苏宁电器
4分钟前 发表
读的还是之前的数据【老牛】
本站网友 元素粘稠物
15分钟前 发表
经常一篇文章从周一写到周末才能完成
本站网友 nexus3
23分钟前 发表
我们简单举例说一下: 如下图
本站网友 焦点访谈联系方式
14分钟前 发表
继续多次查询
本站网友 赵燕明
3分钟前 发表
以及新增写入
本站网友 人民币汇率改革
11分钟前 发表
支持大家持续学习分享交流
本站网友 奥维通信股票
4分钟前 发表
age
本站网友 肝炎早期症状
29分钟前 发表
包括家庭
本站网友 什么是前列腺炎
10分钟前 发表
比如读已提交隔离级别下
本站网友 正天丸
11分钟前 发表
不可重复读三大事务并发问题
本站网友 中国银行外汇牌价网
30分钟前 发表
不可重复读
本站网友 仁和春天光华店
3分钟前 发表
我们不会简单的直接进行update
本站网友 凡客网址
30分钟前 发表
最终全年得到作者热度89的排名
本站网友 入党有什么好处
6分钟前 发表
到了下一个事务id=99的数据【老牛】
本站网友 笔记本键盘失灵
8分钟前 发表
幻读问题demo详解 新建一个user_mvcc_demo表
本站网友 eu400
4分钟前 发表
把name改为=【老牛】
本站网友 硬度标准
3分钟前 发表
到了下一个事务id=99的数据【老牛】
本站网友 庭园设计
2分钟前 发表
查询是不会让数据事务发生变化