MySQL 可重复读隔离级别,完全解决幻读了吗?

news2024/11/27 21:01:47

文章目录

  • 前言
  • 一、什么是幻读?
  • 二、快照读是如何避免幻读的?
  • 三、当前读是如何避免幻读的?
  • 四、幻读被完全解决了吗?
    • 场景1
    • 场景2
  • 总结


前言

MySQL InnoDB 引擎的默认隔离级别虽然是「可重复读」,但是它很大程度上避免幻读现象(并不是完全解决了),解决的方案有两种:

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
  • 针对当前读(select … for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。

这两个解决方案是很大程度上解决了幻读现象,但是还是有个别的情况造成的幻读现象是无法解决的。

一、什么是幻读?

首先来看看 MySQL 文档是怎么定义幻读(Phantom Read)的:

The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

翻译:当同一个查询在不同的时间产生不同的结果集时,事务中就会出现所谓的幻象问题。例如,如果 SELECT 执行了两次,但第二次返回了第一次没有返回的行,则该行是“幻像”行。

举个例子,假设一个事务在 T1 时刻和 T2 时刻分别执行了下面查询语句,途中没有执行其他语句:

SELECT * FROM t_test WHERE id > 100;

只要 T1 和 T2 时刻执行产生的结果集是不相同的,那就发生了幻读的问题,比如:

  • T1 时间执行的结果是有 5 条行记录,而 T2 时间执行的结果是有 6 条行记录,那就发生了幻读。
  • T1 时间执行的结果是有 5 条行记录,而 T2 时间执行的结果是有 4 条行记录,也是发生了幻读。

二、快照读是如何避免幻读的?

可重复读隔离级是由 MVCC(多版本并发控制)实现的,实现的方式是开始事务后(执行 begin 语句后),在执行第一个查询语句后,会创建一个 Read View,后续的查询语句利用这个 Read View,通过这个 Read View 就可以在 undo log 版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,即使中途有其他事务插入了新纪录,是查询不出来这条数据的,所以就很好了避免幻读问题。

做个实验,数据库表 t_stu 如下,其中 id 为主键。

然后在可重复读隔离级别下,有两个事务的执行顺序如下:

在这里插入图片描述

从这个实验结果可以看到,即使事务 B 中途插入了一条记录,事务 A 前后两次查询的结果集都是一样的,并没有出现所谓的幻读现象。

三、当前读是如何避免幻读的?

MySQL 里除了普通查询是快照读,其他都是当前读,比如 update、insert、delete,这些语句执行前都会查询最新版本的数据,然后再做进一步的操作。

这很好理解,假设你要 update 一个记录,另一个事务已经 delete 这条记录并且提交事务了,这样不是会产生冲突吗,所以 update 的时候肯定要知道最新的数据。

另外,select … for update 这种查询语句是当前读,每次执行的时候都是读取最新的数据。

接下来,我们假设select … for update当前读是不会加锁的(实际上是会加锁的),在做一遍实验。

在这里插入图片描述

这时候,事务 B 插入的记录,就会被事务 A 的第二条查询语句查询到(因为是当前读),这样就会出现前后两次查询的结果集合不一样,这就出现了幻读。

所以,Innodb 引擎为了解决「可重复读」隔离级别使用「当前读」而造成的幻读问题,就引出了间隙锁。

假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。

在这里插入图片描述

举个具体例子,场景如下:

在这里插入图片描述

事务 A 执行了这面这条锁定读语句后,就在对表中的记录加上 id 范围为 (2, +∞] 的 next-key lock(next-key lock 是间隙锁+记录锁的组合)。

然后,事务 B 在执行插入语句的时候,判断到插入的位置被事务 A 加了 next-key lock,于是事物 B 会生成一个插入意向锁,同时进入等待状态,直到事务 A 提交了事务。这就避免了由于事务 B 插入新记录而导致事务 A 发生幻读的现象。

四、幻读被完全解决了吗?

场景1

下面是一个幻读的场景,依序号执行操作:

在这里插入图片描述

这是因为操作7是一个当前读,而当前读都是读取到的最新的数据,所以客户端2在事务中提交的数据可以被看到,发生了幻读!


场景2

下面也是一个幻读的场景,依序号进行操作:

在这里插入图片描述

对于操作三,我们先查询 id=5 的数据,发现没有,然后再通过客户端提交一个插入 id=5 的事务,这是我们进行操作六,发现查询不到数据,但是却能更新,而更新后就能查到了!

这是一个匪夷所思的现象!我们试着分析一下原因:

在可重复读隔离级别下,事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 5 的记录并提交。接着,事务 A 对 id = 5 这条记录进行了更新操作,在这个时刻,这条新记录的 trx_id 隐藏列的值就变成了事务 A 的事务 id(此时trx_id和ReadView中的creator_trx_id相同,表示当前存在它自己修改过的记录,所以这条记录可以被获取),之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了,于是就发生了幻读。

用到的规则如下(上述规则出自《資料庫解剖學:從內部深解MySQL運作原理》):

对应源码可以证明规则1:

在这里插入图片描述

下面的例子可以验证上述规则1:

在这里插入图片描述

总结

上面两种场景可以总结为一种情况,那就是先进行快照读,再插入,然后执行当前读,比如 update、insert、delete、select…lock in share mode (共享读锁)、select…for update等操作时,会读取到最新的数据,所以会出现幻读

要避免这类特殊场景下发生幻读的现象的话,就是尽量在开启事务之后,马上执行 select … for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1425720.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Qt学习笔记】(二)信号和槽

信号和槽 1 信号和槽概述2 信号和槽的使用3 可视化生成槽函数4 自定义信号和槽5 带参数的信号和槽6 信号与槽的连接方式7 信号与槽的断开8 使用 Lambda 表达式来定义槽函数 1 信号和槽概述 在Qt中,用户和控件的每次交互过程称为一个事件。比如"用户点击按钮&q…

动网格-网格重构之弹性光顺局部重构法(四)

弹性光顺法的基本特点 弹性光顺法中,网格线类似于弹簧,两端节点(node)作弹性移动 弹性光顺法有如下特点。 (1)节点的数量和节点之间的连接关系均不变,即节点之间的连接属性不变。 (2)单独使用时,仅限于变形非常小的情况&#xff…

Ubuntu-22.04上使用硬解码播放视频

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、准备工作1.显卡驱动2.其它必须软件3.查看显卡支持哪些编码格式 二、SMplayer三、VLC总结 前言 现在Ubuntu做的越来越好了,很多人拿它来当主力机…

深度解读NVMe计算存储协议-1

随着云计算、企业级应用以及物联网领域的飞速发展,当前的数据处理需求正以前所未有的规模增长,以满足存储行业不断变化的需求。这种增长导致网络带宽压力增大,并对主机计算资源(如内存和CPU)造成极大负担,进…

【Tomcat与网络10】Tomcat I/O和线程池的并发调优

前面我们看了提高Tomcat启动速度的措施,这里我们看一下如何提高Tomcat的性能。 Tomcat 的调优涉及 I/O 模型和线程池调优、JVM 内存调优以及网络优化等,今天我们来聊聊 I/O 模型和线程池调优,由于 Web 应用程序跑在 Tomcat 的工作线程中&…

月入过万比打工强,在家就能做steam搬砖项目真的假的

每天都有粉丝私下跟我聊天,讨论Steam搬砖项目到底是不是真的,到底能不能做。你想让我详细说说。那么今天就和大家详细聊聊这个月入过万元的项目。 简单来说,Steam搬砖项目就是在国外蒸汽上采购游戏道具,在国内网易buff平台上销售…

外包干了10个月,技术退步明显.......

先说一下自己的情况,大专生,18年通过校招进入武汉某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

面对近期行情大起大落的伦敦银需要关注什么?

近期经常有听到投资者抱怨说,伦敦银价格没有明显趋势,很难做。确实,我们从日线图看,金价处于一个比较宽幅的横盘区间当中,近期的行情也是大涨大跌。投资者认为,面对大起大落的行情无从下手。下面我们就来讨…

【WebGIS实例】(13)MapboxGL+Vue 实现自定义组件地图气泡弹窗 popup

前言 没有前言,直接上代码了 代码 核心方法 const addComponentPopup (component, feature, lnglat, map) > {const popup new mapboxgl.Popup({// anchor: center, // center , top , bottom , left , right , top-left , top-right , bottom-left , and …

【JavaSE篇】——内部类

目录 🎓内部类 🎈内部类的分类 🚩实例内部类 一.如何实例内部类对象 二.实例内部类中为什么不能有静态成员变量 (用final解决) 三.在实例内部类对象时,如何访问外部类当中相同的成员变量?…

MySQL数据库-理论基础

1.1 什么是数据库 数据: 描述事物的符号记录, 可以是数字、 文字、图形、图像、声音、语言等,数据有多种形式,它们都可以经过数字化后存入计算机。 数据库: 存储数据的仓库,是长期存放在计算机内、有组织…

Collection和Map集合

Collection分两大类:List和Set List又分为:ArrayList和LinkedList Set分为HashSet和TreeSet List集合特点:添加的元素有序,可重复,有索引 ArrayList和LinkedList:有序,可重复,有索引 Set集合特点:添加的元素是无序,不重复,无索引 HashSet:无序,不重复,无索引 Lin…

Android源码设计模式解析与实战第2版笔记(四)

第三章 自由扩展你的项目–Builder 模式 Builder 模式的定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 Builder 模式的使用场景 相同的方法,不同的执行顺序,产生不同的事件结果时 多个部件或零件&…

【升级openssl1.1.1t报错libssl.so.1.1: cannot open shared object file】

升级openssl报错: openssl vesion openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory 编译安装openssl1.1.1t当执行openssl version的时候,报上述错误,将编译到的…

【昕宝爸爸小模块】日志系列之什么是分布式日志系统

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。 本文章CSDN首发,欢迎转载,要注明出处哦! 先感谢优秀的你能认真的看完本文&…

2.1总结

还是一样水更一天,就随便做了几个题,有一个周期有点长,后面更一篇长的 随手刷的一道水题,就不往今天的行程单添了 问题:最大公约数 题解:题目太水了,就是求三个数,其中两组的最大公…

[前端]node多版本控制器nvm

文章目录 nvm下载安装查看目前可用版本安装完之后查看版本查看镜像源与npm所有配置修改镜像源与npm配置安装结束 nvm下载安装 https://github.com/coreybutler/nvm-windows/releases 不方便的可使用百度云下载 链接:https://pan.baidu.com/s/1gDUMpbYdz24dHmedPEKR…

BSV区块链将凭借Teranode的创新在2024年大放异彩

​​发表时间:2024年1月15日 2024年1月15日,瑞士楚格 – BSV区块链协会研发团队今日官宣了Teranode的突破性功能,这些功能将显著提升BSV区块链网络的效率和速度。在不久的将来,BSV区块链的交易处理能力将达到每秒100万笔交易。 T…

基于springboot+vue的校园赛事资讯网站(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Unity 策略模式(实例详解)

文章目录 简介示例1:角色攻击行为示例2:游戏内购折扣策略示例3:NPC寻路策略示例4:动画过渡策略示例5:敌人AI决策策略 简介 在Unity中使用策略模式,我们可以将不同的行为或算法封装成独立的类(策…