当前位置: 首页 > news >正文

浅谈Mysql的MVCC机制(RC与RR隔离级别)

MVCC(Multi-Version Concurrency Control)多版本并发控制

说这个我们先来了解一下Mysql的隔离级别,因为MVCC和Mysql的隔离级别是有关的。

Mysql默认的隔离级别是RR(可重复读)

其他的隔离级别是读未提交(RU)读已提交(RC)、可重复读(RR)、可串行化

读未提交我们知道会产生脏读,脏读也就是一个事务读到另外一个事务未提交的数据,造成数据不一致问题。

读已提交不会造成脏读,从名字来看就是已提交,就是解决读未提交产生的问题,它不会产生脏读,但是它会产生不可重复读,不可重复读,指的就是一个事务一直读取同一条记录,但是会被其他事务的更新操作影响到读取的结果,造成数据不一致。

举个例子:

这时候最后一条读出来的结果就是zhangsan了。

这就是不可重复读。

可重复读,从名称上来看就是可以重复select,也就是为了解决读已提交造成的不可重复读。

那么你们有没有想过,为什么读已提交不会造成读未提交产生的脏读,却会造成不可重复读呢?可重复读为什么不会造成读已提交产生的不可重复读呢?其实背后都是MVCC控制的。

MySQL中的行数据,除了我们肉眼能看到的字段之外,其实还包含了一些隐藏字段,它们在内部使用,默认情况下不会显示给用户。

字段含义
DB_ROW_ID隐含的自增ID(隐藏主键),用于唯一标识表中的每一行数据,如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。
DB_TRX_ID该字段存储了当前行数据所属的事务ID。每个事务在数据库中都有一个唯一的事务ID。通过 DB_TRX_ID 字段,可以追踪行数据和事务的所属关系。
DB_ROLL_PTR该字段存储了回滚指针(Roll Pointer),它指向用于回滚事务的Undo日志记录。

Read View

一致性视图,会用一个列表存放当前活跃的事务ID,也就是未提交的事务,当我们事务进行select 读操作的时候,就会生成这么一个ReadView视图,ReadView就会判断undo log版本链中的哪个版本对当前事务是可见的

这里提到了Undo log那我们就看看这个是什么东西,就是为了进行版本回滚的。

维护了一条版本链,链上都是每一行记录,包括刚刚提到的trx_id事务id,row_id,roll_pointer

当我们对数据进行更新的时候,会先将更新前原记录进行拷贝,然后undo Log日志就会开始存放,每次更新的时候都是这样,至此就会形成一条版本链。

那么ReadView是怎么判断哪些事务ID是可见的呢?

从Undo Log 版本链中的第一条记录开始往前找,获取当前版本的trx_id 事务id,只要事务ID在活跃的事务列表里面,那肯定是不可见的,如果比最小事务ID小,也是不可见,比最大事务ID还大,那也是不可见,也就是说只有在最小事务ID和最大事务ID之间才是可见的。

我们可以简单的举一个例子:

T4 时刻事务C查询的结果是什么呢?

我们看现在活跃的事务id有100,

最小事务ID是100,

最大事务ID是400,

那么从Undo Log版本链中找

第一条事务ID是100,100在活跃的事务列表里面,不可见。(所以这就验证了为什么RC级别下不会造成读未提交产生的脏读,未提交的在列表里面,直接不可见了)

继续往前找,还是100,还是不可见,

继续往前找,1,1不在事务ID列表里面,继续判断1是不是等于当前生成ReadView视图的事务ID300?不等于,1是否大于最大事务ID100?不大于。继续判断1是否小于最小事务ID100,1<100可见,所以RC级别下此时select查询出来的结果就是小明。RR也是小明。

我们来看一下T6时刻,如果是RC级别下,此时Undo Log的版本链是长这样的:

此时活跃的事务ID列表有:200,

最小事务ID是200,

最大事务ID是400,

创建ReadView视图的当前事务ID是300

从第一个版本看,200,在活跃的事务ID列表里面,不可见,

继续向前找200,还是在活跃的事务ID列表里面,不可见,

继续向前找,100,100 不在活跃的事务ID列表里面,100也不等于创建当前ReadView的事务ID300,100比最小事务ID还小,可以访问,所以RC级别下读到的结果就是小红,那么如果是RR级别下读到的是什么呢?还是小明,因为RR级别的ReadView视图会一直延用第一次相同Select创建的ReadView,这也就是为什么RR级别不会造成不可重复读,而RC会造成不可重复读的原因,RC每次Select创建的ReadView视图都是新创建的,而RR都是延用第一次Select产生的ReadView视图。所以也就验证了前面的那个疑问:为什么读已提交不会造成读未提交产生的脏读,却会造成不可重复读呢?可重复读为什么不会造成读已提交产生的不可重复读呢?

总结:

        RC级别下,select的时候ReadView视图每次都是会创建新的,所以这就是会造成不可重复读的原因;ReadView在判断版本链中哪个版本对当前事务可见的时候,如果是未提交的事务ID,是直接不可见的,这就是为什么不会造成脏读的原因。

        RR级别下,Select的时候ReadView视图都是延用第一次Select创建的ReadView视图,而不会产生新的ReadView视图,这也就是为什么RR级别不会造成不可重复读的原因。

http://www.xdnf.cn/news/677683.html

相关文章:

  • LeetCode 1696. 跳跃游戏 VI(中等)
  • AI Agent开发第75课-数据、张量、流水线并行全解析
  • 【Web应用】若依:基础篇03-入门案例,若依代码生成器生成前后端代码
  • Web通信协议全景解析:从HTTP到WebService的技术演进与对比
  • 如何寻找大模型在企业业务中的价值?
  • Anaconda下载安装+配置虚拟环境保姆级教程(2025版)
  • 实时数仓flick+clickhouse启动命令
  • 第一个ASP.NET项目
  • 【Elasticsearch】retry_on_conflict
  • Python中while 1和while True有何区别?深入解析无限循环的写法选择
  • 百胜咨询公司:企业EcoVadis认证的专业导航者
  • SIGGRAPH 2025 | 快手可灵团队提出3D感知的电影级文本到视频生成框架CineMaster
  • 鸿蒙5开发宝藏案例分享---一多断点开发实践
  • 0527漏洞原理:SQL注入笔记 SQL注入类型(联合查询注入、报错注入实操)
  • 【本地部署】 Deepseek+Dify创建工作流
  • 【Vue 3 运行时 Diff 算法深度解析:五步走策略实现高效更新】
  • MySQL数据库第一章
  • 科技趋势分析系统 BBC (Big Bang of Computing)
  • mysql中的索引怎么用?
  • [特殊字符]《计算机组成原理》第 8 章 - CPU 的结构和功能
  • 本地部署 DeepSeek
  • 计算机组成原理——指令的寻址方式
  • 迪米特法则 (Law of Demeter, LoD)
  • 多个vue2工程共享node_modules
  • Liunx部署ES单机集群
  • Streamlit 项目知识点总结
  • OpenCv高阶(十三)——人脸检测
  • 第二章:软盘里的90年代
  • 力扣四道题,力扣LCR 016无重复字符的最长子串力扣452.用最小数量的箭引爆气球LCR026.重排链表力扣.1765地图中的最高点
  • 猿大师办公助手WebOffice用二进制数据流在Web前端打开Office文档