当前位置: 首页 > 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级别不会造成不可重复读的原因。

相关文章:

  • 定时清理流媒体服务器录像自动化bash脚本
  • 为My Retro应用添加安全防护
  • 线程池详解:原理、使用与优化
  • 机器学习算法-- K 近邻算法(KNN)
  • 关于空调温度控制仿真模型的详细技术文档,包含数学模型、Python实现和系统分析
  • 丰富案例库:解锁智能门锁行业唯创语音交互方案的应用优势
  • 小土堆pytorch--现有网络模型的使用及修改
  • 在PyTorch中,有了y = x + y,为什么还需要y += x,有什么好处呢?
  • cursor使用mcp
  • 基于Matlab实现各种光谱数据预处理
  • 数据库相关问题
  • 工控安全审计与网络流量监控系统的协同防御
  • 字节跳动推出开源多模态模型 BAGEL 从图像生成到世界建模
  • Solana账户创建与Rust实践全攻略
  • 什么是Windows内存压缩? win10/11系统启用和禁用内存压缩的教程
  • 图标变白,开始菜单栏无法打开程序(以jupyter为例)
  • 让jupyter notebook显示目录
  • Lua中的`self`参数:揭秘隐藏的“对象上下文”
  • Word 目录自动换行后错位与页码对齐问题解决教程
  • Spring Security Token 认证原理
  • 河北省建设机械协会官方网站首页/深圳网络推广网站
  • 当今做网站的流行/广州网络推广服务商
  • 手机上制作ppt的软件/福州短视频seo机会
  • 网站建设的内容管理/网站权重排名
  • 当前网站开发什么语言/企业网站的功能
  • 公司网站建设亚运村/福州seo管理