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

MySQL—隔离级别和MVCC

前言

还是像我剖析线程池的时候所说,我感觉我确实走的太快了,不过学的早的好处就是可以随时调整,那不如我们现在朝花夕拾一下,后面几个博客估计也都是MySQL

正文

并发问题

隔离级别是因为并发问题而生的,那到底MySQL会有哪些并发问题

误区

  • 这里大家可能会进入一个误区,我发现别人更新的数据不是很正常吗,我就是在获取最新的这个数据
    但是大家要注意,这里是一个事务,事务具有隔离性(这里破坏的就是隔离性),从表现上来看。这里我一个事务具有原子性,两次操作查询的目标应当一致,所以不可重复读和幻读我觉得也是破坏原子性的一个体现(这个不是标准,只是帮助理解,这个话不要记,因为这里本身在一个线程里面这里的两个操作看起来就是无缝执行的,所以其实符合原子性

脏读

这个就是🈯️线程A正在修改这个SQL数据,这个时候事务没有提交,这个时候线程B来查询这个数据,但是这个时候获取到了线程A还未修改的数据

不可重复读

这个指的就是线程A有两次查询操作,第一次查询比如是100,但是中途线程B来修改数据,把这里的100修改成了1000,然后A第二次执行查询操作,发现这里是1000,同一个事务里面两次读取不一致

幻读

  1. SQL经典定义
    这个指的就是比如我线程A还是查询两次,第一次查询当前有5行数据,线程B再插入一条(对空白线程A 不操作的地方做操作),第二次线程A查询发现有6条数据,就像出现了幻觉,这个就叫幻读
  2. MySQL RR级别 InnoDB独有现象
    这里指的就是比如我线程A读一下我这个数据里面只有1 3 5,然后线程B插入一个4,然后我这个A的第二个操作恰好也是插入一个4,发现冲突,线程A再读,发现只有1 3 5没有4。这个就像幻觉一样,这个也是幻读

隔离级别

这里企业大多使用RC或者RR,大部分都是RC,因为这里越往下,并发性能也就越差,特别是这里的串行化,堪比单线程的
想看这里的实现原理,这里必须得看看下面的MVCC

  1. 读未提交(read uncommited):意思就是如果这个时候你没有提交,我也可以看到你的数据
  2. 读已提交(read committed RC):这里的意思就是我只能看到你提交后的数据**(这里的实现是引入了快照读)**
  3. 可重复读(repeatable read RR):意思就是这里你开始我看到你什么样,执行过程中也看你什么样**(这里的解决方案是一个事务只有一个快照)**
  4. 串行化(serializable):这个就是多个事务之间发生读写冲突的时候,得排队,一个事务一个事务来(堪比单线程)

这个就是不同级别可能出现的问题,但是MySQL的RR可以很大程度避免幻读,但是无法完全避免幻读

MVCC

这个东西就是数据库来实现上面四种隔离级别的利器和基础了

当前读和快照读

  1. 快照读:只有普通的select语句是快照读,这里会生成一个快照,里面只有已提交的事务
  2. 当前读:比如select … for update或者insert或者update或者delete都是当前读,这里就会提交这里的数据。
  • 现在看是不是感觉没区别,等一会MVCC到RR的时候你们就会发现明显区别**(其实也很明显,只有快照读可以访问版本链,而当前读直接读最新数据来)**
  • 而RR级别为什么不可以完全解决幻读也是因为这里的当前读和快照读的冲突

数据库隐藏字段

首先是数据库隐藏字段

  1. DB_TRX_ID:这个是最近修改事务的ID
  2. DB_ROLL_PTR:这个是回滚指针,指向上一次事务的修改,也就是指向上一个版本
  3. DB_ROW_ID:这个是隐藏主键,如果没有主键字段就是用这个做主键

undolog版本链

概念

undolog是事务原子性的基础,当我们执行一条非查询的语句,比如insert,这里的undolog就会生成一个对应的delete,用于回滚,而这里的日志更新时机就是在执行语句真正执行前,这里就更新了日志(防止你断个电啥的造成损失,即使宕机,也可以回滚)
而undolog的第二个作用就是来帮我生成一个版本链(如图所示),这里就像链表,这里的头节点是最新的记录,每次使用头插法来插入新版本

快照读的相关属性

这里直接贴一张来自黑马程序员的图,我们一会讲案例的时候回来查

数据链访问规则(快照读)
  • 注意
    • 这里RR和RC的区别就是在于这里,RR每个事务只有一张快照,但是RC每次查询都会有快照,这个时候就会导致一个问题就是每次RC其实查询到的就是最新的已提交的数据(这个时候就触发了不可重复读和幻读),但是不用判断这里的数据链访问规则
    • 所以说这里的数据链访问规则就是给RR准备的,那我们看看这里是如何访问数据链的
    • 这里首先你要先去上面看ReadView的属性,在这个数据链访问规则还是很重要的
  • 比如这里我们的m_ids就是1,3,5(但是要注意快照读访问的就是已提交的事务,这里相当于一个黑名单)
  1. 关于这里的第一条规则,没什么说的,我创建的我还不可以访问了?
  2. 关于第二条规则,这里就是不在黑名单里面你就相当于提交了,所以这里可以访问
  3. 如果大于max就说明你不在我这个快照里面,无法读
  4. 第四个就说这个如果不在黑名单就可以访问
临键锁 <next-key锁>(当前读)

在RR隔离级别里面,对于当前读的防范就在这里,这里就是临键锁(行锁+间隙锁)
行锁可以防止不可重复读的问题,间隙锁可以避免大部分幻读问题(比如访问1,3,这里就会(-∞,1], (1,3], (3,+∞)锁住,防止别的线程插入数据),但是相应的这里的并发性能就会下降,因为其他的线程阻塞了
我们来一个例子理解一下,我们就看一下这个InnoDB在RR对临键锁的优化吧

比如我们现在有一组数据:10,20,20,30,40对应id:1,2,4,5,6

  1. 对于第一种情况:我们找一个id=3吧,就临键锁锁住这里的2-4,然后发现3不在,把临键锁退化为间隙锁,防止这里另一个进程插入一个3导致幻读
  2. 对于第二种情况:这里我们建立一个索引吧,然后通过这个索引来找这里=20的值,这里(10,20]加临键锁,(20,20]临键锁,(20-30]加临键锁。(如果这里没有20的话,这里就会锁(10,30)并且退化为间隙锁<第一种情况>)
    - 易困惑点:这里其实只需要锁一下这两条20以及这里的间隙就够了。但是这里其实多锁了一个30,因为这里数据命中了,这里无法从临键锁退化到间隙锁
  3. 对于第三种情况:这里我们查询id<4的值吧,这里(-∞,1]临键锁,(1,2]加临键锁,(2,4)加间隙锁
    - 目的:防止对这里id<4的值做改动
无法解决的冲突(RR)

看似这里我们有undolog版本链来防范快照读的幻读,有临键锁来防范当前读的幻读,那还有什么幻读是我们干不了的,这里能有什么问题。那其实小林coding就给出了两个场景,那也就是我们定义里面说的两个定义

  1. 场景一
    这里我们线程A来查询一下数据5,表中没有,所以查询不出来,这里线程B插入了一个数据5,现在A再来查询(快照读当然查不出来),这个时候A对数据5做一个更新操作(当前读当然可以更新),这个时候再去读,这个时候发现这个操作id是自己,就可以读到了
  2. 场景二
    这里我们线程A查询一下>100的数据,发现有3条,然后这个时候B插入一条200,这个时候A使用for update查询,发现有4条,就是我们说的SQL的经典幻读定义(这里的解决方案就是这里一旦开启事务就使用for update,也就是统一使用当前读
  • 其实总结来看,就是一个事务使用了当前读和快照读导致两种读法出现冲突

尾声

其实从企业的方面来看,他们不在乎不可重复读和幻读,只要不出现脏读就好,所以这里其实大家都为了这个并发性能大多业务都是RC,而这里的RR,只有涉及一些重要业务的时候使用,包括一些别的数据库,默认都是RC,所以说我觉得只需要重点关注一下RR和RC就好

http://www.zskr.cn/news/1418629.html

相关文章:

  • 百度网盘提取码智能查询:3步告别资源获取烦恼的终极指南
  • 不是所有 AI 产品都适合出海,真需求和全球化幻觉差在哪? | 嗨点小圆桌
  • Docker 网络进阶:容器间通信与 DNS 解析
  • Arduino旋转电位器应用:从模拟信号读取到Processing数据可视化
  • 北斗导航“指路”申通西安转运中心让特产寄递跑出“加速度”
  • Arduino电子钢琴DIY:从电路设计到C++编程的嵌入式音乐项目实践
  • 别只盯着地图!深度解析ArcGIS Pro内容窗格的5个隐藏选项卡(选择、编辑、捕捉…)
  • 0104摩尔定律死亡终审:性能提升唯一路径——放弃几何微缩,转向场域升维+时间重构
  • 新手也能搞定的TPS5430电源设计:从24V到15V,手把手教你选对每个元器件(附完整BOM清单)
  • ArcMap新手必看:三种要素选择方法(按属性、位置、图形)的保姆级图文教程
  • Arm CoreLink NIC-400与NI/NoC动态调频技术详解
  • 从实验室到产线:Imatest枯叶图在摄像头批量质检中的实战应用与自动化脚本思路
  • 告别死板教程!用ShaderGraph复刻《和平精英》动态海面,这5个参数调好了效果直接翻倍
  • C语言在嵌入式Linux系统开发中的实战应用
  • PriLLM: 为LLM服务实时定价的 Stackelberg Game 建模 【School of CS and Eng,Southeast University】
  • 别再只会拖Button了!用Python脚本+Unity UGUI EventSystem,5分钟自动化测试你的UI交互
  • OpenCV 4.x时代,如何用ORB替代SIFT搞定Python图像拼接(附完整代码)
  • 避坑指南:Unity ShaderGraph制作透明火焰效果时,Alpha混合和Surface设置的那些坑
  • 别再死记硬背了!用Python实战模拟四种循环(简单/嵌套/连锁/非结构)的测试用例设计
  • 亚控组态报表数据导出Excel后,如何用VBA实现自动汇总与图表生成?
  • 技术美术进阶:三方向映射纹理的“坑”与优化技巧(从UE4到Unity的避坑指南)
  • 保姆级教程:理光喷头UV打印机白墨与光油通道设置实战(以1H2C_4C+2WV为例)
  • Oracle数据清洗实战:用正则表达式搞定脏数据,附赠常用SQL模板
  • Yolov8全系列模型C#推理性能优化:TensorRT vs. OpenVINO C# API对比实测
  • 工业网关实战:基于神州龙芯GSC3290双网口与YT8521S的稳定网络方案设计与调试心得
  • RuoYi-Vue + PostgreSQL实战:除了改驱动和URL,这些配置细节你调对了吗?
  • 手把手教你用Vivado 2019.1配置Tri Mode Ethernet MAC,搞定FPGA与RTL8211E的千兆UDP通信
  • 别再手动折腾了!用Composer和PECL一键搞定PHPStudy的imagick扩展(附PHP7.3/7.4版本适配指南)
  • 告别偏色!手把手教你用i1Profiler 3.5为打印机制作精准ICC曲线(附D50/D65光源选择指南)
  • AI搜索变天后,最先掉队的不是小网站,而是还没搞懂向量引擎的人