简聊MySQL并发事务中幻读、虚读问题的解决方案

        在MySQL数据库中,事务的幻读和虚读问题是并发控制中的关键挑战。以下是针对这两个问题的解决方案及原理说明,并附上相关示例。

一、幻读问题及其解决方案

  1. 幻读问题的定义

        幻读是指一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行,这通常是由于其他事务在这个范围内插入了新的数据。

  1. 解决方案及原理

    • 提高事务隔离级别:将事务的隔离级别设置为串行化(Serializable)可以彻底避免幻读问题。在这种隔离级别下,事务会完全隔离,其他事务无法在其执行期间插入新的数据。然而,这种解决方案会导致性能显著下降,因为串行化隔离级别会限制并发性。
    • 使用MVCC(多版本并发控制):MVCC通过为每个事务分配一个唯一的事务ID和版本号,来保证每个事务读取到的数据都是一致的。当一个事务开始时,它会生成一个快照,后续的读取操作都会从这个快照中获取数据,从而避免了幻读问题。MySQL在可重复读(Repeatable Read)隔离级别下,通过MVCC机制来减少幻读问题的发生。
    • 引入Next-Key Lock:在InnoDB存储引擎中,除了行锁之外,还引入了间隙锁(Gap Lock)和Next-Key Lock来解决幻读问题。Next-Key Lock是行锁和间隙锁的组合,它锁定了一个范围,包括索引记录以及它们之间的空隙。当执行范围查询并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,同时也会对键值在条件范围内但并不存在的记录(即间隙)加锁。这样,其他事务就无法在这个范围内插入新的数据,从而避免了幻读问题。
  2. 示例

    • 假设有一个名为products的表,其中包含idname两列。
    • 事务A执行查询操作:SELECT * FROM products WHERE id > 100;
    • 事务B在事务A查询的范围内插入一条新的数据:INSERT INTO products (id, name) VALUES (150, 'New Product');并提交事务。
    • 事务A再次执行相同的查询操作:SELECT * FROM products WHERE id > 100;
      • 在没有使用间隙锁的情况下,事务A的第二次查询将会返回新增的数据,导致幻读的问题出现。
      • 如果在事务A的查询语句中加入FOR UPDATE,即 SELECT * FROM products WHERE id > 100 FOR UPDATE;,这样事务A在读取数据的同时,会对查询范围内的间隙进行锁定,从而阻止了其他事务的插入操作,避免了幻读的发生。

二、虚读问题及其解决策略

        虚读问题通常是指在可重复读(Repeatable Read)隔离级别下,一个事务读取到另一个事务已经提交但尚未对当前事务可见的数据。然而,在MySQL的InnoDB存储引擎中,由于实现了MVCC机制,实际上在可重复读隔离级别下并不会发生虚读问题。因为MVCC确保事务读取到的数据是事务开始时的快照,即使其他事务在之后对数据进行了修改或提交,也不会影响到当前事务的读取结果。

三、总结

        MySQL通过提高事务隔离级别、使用MVCC机制以及引入Next-Key Lock等策略,有效地解决了幻读问题。同时,由于MVCC机制的实现,MySQL在可重复读隔离级别下实际上并不会发生虚读问题。在实际应用中,开发者需要根据具体的业务场景和需求选择合适的解决方案,以确保数据的一致性和系统的性能。

四、解释“SELECT ...... FOR UPDATE;

        当您在MySQL的InnoDB存储引擎中使用SELECT ... FOR UPDATE语句时,如果查询条件涉及范围查询(如id > 100),InnoDB会自动为该查询添加Next-Key Lock。Next-Key Lock是InnoDB实现的一种锁策略,它结合了行锁(Record Lock)和间隙锁(Gap Lock)来避免幻读问题。

具体来说,当您执行SELECT * FROM products WHERE id > 100 FOR UPDATE;时,InnoDB会:

  1. 对满足条件id > 100的每一行数据加上行锁(Record Lock),确保其他事务不能修改或删除这些行。
  2. 同时,InnoDB还会对id值在100到查询结果中最小id值之间的间隙(Gap)加上间隙锁(Gap Lock),以及查询结果中最大id值到正无穷大之间的间隙加上间隙锁(如果存在的话,实际上在大多数情况下,我们不会关心正无穷大这个边界的间隙锁,因为它不影响插入操作)。这样,其他事务就不能在这个间隙内插入新的数据行。

通过结合行锁和间隙锁,Next-Key Lock能够确保在事务执行期间,查询结果集不会被其他事务修改或插入新行,从而避免了幻读问题。

需要注意的是,虽然SELECT ... FOR UPDATE会添加Next-Key Lock,但只有在事务隔离级别为可重复读(Repeatable Read)或更高(实际上是串行化,但串行化通常不会用于实际应用中,因为它会极大地降低并发性能)时,这种锁策略才会生效。在读已提交(Read Committed)隔离级别下,InnoDB不会使用间隙锁,因此可能会遇到幻读问题。

五、注意navicat中测试记录锁Gap Locks示例:

        确保事务隔离级别是RR: 

1、打开两个查询窗口:

        相当于开启了两个事务;

        窗口1是开启事务并加记录锁;

        窗口2是执行update、insert、delete等DML操作;

窗口1内容:        

        解释:测试时, “运行已选择的” 图表灰色不可点击说明是开启事务成功;“停止”图表亮起,表示添加行锁记录锁;阻塞了,其他窗口就不能对此行记录进行操作了。

窗口2内容:           

         解释:同窗口1的解释。执行update语句没有成功,在等待其他事务释放锁。

2、两个窗口分别关掉停止

窗口1关掉停止,显示: 

SELECT * FROM EMP WHERE ID=1001 FOR  UPDATE
> 1205 - Lock wait timeout exceeded; try restarting transaction
> 时间: 50.591s

窗口2关掉停止,显示: 

update  EMP set ename='天天向上杰4'  where  ID=1001
> 1205 - Lock wait timeout exceeded; try restarting transaction
> 时间: 51.439s

3、注意⚠️错误示范

        千万不要在一个查询窗口中执行啊,切记!错误示范:

              (有不对的地方,大家多多批评,并发表出您的真知,感谢)  上述这样不会执行成功的。因为在同一个会话中,执行语句的顺序是从上到下,相当于在极短的时间内开启事务后,迅速就提交了。在按照顺序执行过程中,等不及锁加载和阻塞,直接就提交执行下一个事务了。 

        用plsqldev.exe操作Oracle时是很好测试的。(略)

        祝大家测试成功!

六、间隙锁简易示例:

间隙锁用于锁定索引记录之间的“间隙”,但不锁定索引记录本身。

示例

  • 假设表your_tableid字段是索引,且有值1、3、5。事务1开始,查询id在1到3之间(不包含1和3)的数据并加锁,会在这个间隙上加间隙锁:        
    • SELECT * FROM your_table WHERE id > 1 AND id < 3 FOR UPDATE;
  • 事务2开始,尝试插入id = 2的数据(会被阻塞,因为有间隙锁):
    • INSERT INTO your_table (id, name) VALUES (2, 'new_entry');

在这个例子中,事务1在1和3之间的间隙上加了间隙锁,事务2尝试插入id = 2的数据时就会被阻塞。

(望各位潘安、各位子健不吝赐教!多多指正!🙏)

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

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

相关文章

WINFORM - DevExpress -> gridcontrol ---->控件(ColumnEdit控件)

ImageComboBoxEdit--带图片的下拉菜单 DevExpress&#xff1a;带图片的下拉菜单ImageComboBoxEdit_weixin_34313182的博客-CSDN博客 ImageEdit--图片按钮 DevExpress控件中的gridcontrol表格控件&#xff0c;如何在属性中设置某一列显示为图片&#xff08;图片按钮&#xff…

IntelliJ IDEA Type Hierarchy Scope Pattern 学习指南

IntelliJ IDEA Type Hierarchy Scope Pattern 学习指南 什么是 Type Hierarchy&#xff1f; Type Hierarchy 是 IntelliJ IDEA 提供的一个工具&#xff0c;允许开发者查看某个类的继承关系及其实现的接口结构。它是理解类关系的重要工具&#xff0c;尤其在处理复杂的继承体系…

分布式ID的实现方案

1. 什么是分布式ID ​ 对于低访问量的系统来说&#xff0c;无需对数据库进行分库分表&#xff0c;单库单表完全可以应对&#xff0c;但是随着系统访问量的上升&#xff0c;单表单库的访问压力逐渐增大&#xff0c;这时候就需要采用分库分表的方案&#xff0c;来缓解压力。 ​…

Python爬虫-汽车之家各车系周销量榜数据

前言 本文是该专栏的第43篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏之前,笔者在文章《Python爬虫-汽车之家各车系月销量榜数据》中,有详细介绍,如何爬取“各车系车型的月销量榜单数据”的方法以及完整代码教学教程。 而本文,笔者同样以汽车之家平台为例,…

Unity-Mirror网络框架-从入门到精通之RigidbodyBenchmark示例

文章目录 前言示例代码逻辑测试结论性能影响因素最后前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开源网络框架,专为多人游戏开发设计,它…

【STM32-学习笔记-7-】USART串口通信

文章目录 USART串口通信Ⅰ、硬件电路Ⅱ、常见的电平标准Ⅲ、串口参数及时序Ⅳ、STM32的USART简介数据帧起始位侦测数据采样波特率发生器 Ⅴ、USART函数介绍Ⅵ、USART_InitTypeDef结构体参数1、USART_BaudRate2、USART_WordLength3、USART_StopBits4、USART_Parity5、USART_Mode…

Linux简介和环境搭建

Linux 介绍和环境搭建 1、发行版本 Linux 操作系统有多个主流发行版本&#xff0c;每个版本根据不同的目标、特点和使用场景为用户提供了不同的功能和体验。 Ubuntu • 特点&#xff1a;Ubuntu 是最为人熟知的 Linux 发行版之一&#xff0c;强调易用性和用户友好性&#xff…

代码随想录刷题day07|(数组篇)58.区间和

目录 一、数组理论基础 二、前缀和 三、相关算法题目 四、总结 五、待解决问题 一、数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。 代码随想录 (programmercarl.com) 特点&#xff1a; 1.下标从0开始&#xff0c;内存中地址空间是连续的 2.查询快&…

多模态论文笔记——CLIP

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍这几年AIGC火爆的隐藏功臣&#xff0c;多模态模型&#xff1a;CLIP。 文章目录 CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09…

【论文笔记】SmileSplat:稀疏视角+pose-free+泛化

还是一篇基于dust3r的稀疏视角重建工作&#xff0c;作者联合优化了相机内外参与GS模型&#xff0c;实验结果表明优于noposplat。 abstract 在本文中&#xff0c;提出了一种新颖的可泛化高斯方法 SmileSplat&#xff0c;可以对无约束&#xff08;未标定相机的&#xff09;稀疏多…

Linux学习day2

经过上次我们完成了linux云服务器的安装&#xff0c;今天我们学习一些linux基本指令&#xff0c;是我们使用linux系统的基础 思考&#xff1a;输入指令&#xff0c;让操作系统执行&#xff0c;其实是在做什么呢&#xff1f; Linux环境中&#xff0c;做类似于windows的操作。l…

给DevOps加点料:融入安全性的DevSecOps

从前&#xff0c;安全防护只是特定团队的责任&#xff0c;在开发的最后阶段才会介入。当开发周期长达数月、甚至数年时&#xff0c;这样做没什么问题&#xff1b;但是现在&#xff0c;这种做法现在已经行不通了。 采用 DevOps 可以有效推进快速频繁的开发周期&#xff08;有时…

【2024年华为OD机试】 (B卷,100分)- 座位调整(Java JS PythonC/C++)

一、问题描述 题目描述 疫情期间课堂的座位进行了特殊的调整&#xff0c;不能出现两个同学紧挨着&#xff0c;必须隔至少一个空位。 给你一个整数数组 desk 表示当前座位的占座情况&#xff0c;由若干 0 和 1 组成&#xff0c;其中 0 表示没有占位&#xff0c;1 表示占位。 …

提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息

网络和IP地址计算器 https://www.sojson.com/convert/subnetmask.html提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息。 子网掩码转换 子网掩码 /26 的含义二进制表示:/26 表示前 26 位是网络部分&#xff0c;剩下的 6 位是主机部分。对应的子网掩码为 255…

IMX6U Qt 开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、交叉编译 1. 安装通用 ARM 交叉编译工具链 2. 安装 Poky 交叉编译工具链 二、编译出厂源码 1. U-boot 2. 内核和模块 3. 编译出厂 Qt GUI 综合 Demo 前言…

【2024年华为OD机试】(B卷,100分)- 找终点 (Java JS PythonC/C++)

一、问题描述 题目描述 给定一个正整数数组&#xff0c;设为 nums&#xff0c;最大为100个成员&#xff0c;求从第一个成员开始&#xff0c;正好走到数组最后一个成员&#xff0c;所使用的最少步骤数。 要求&#xff1a; 第一步必须从第一元素开始&#xff0c;且 1<第一…

RabbitMQ-集群

RabbitMQ集群----主备关系&#xff0c;在运行的时候&#xff0c;如果非主要节点宕机&#xff0c;程序操作 不受影响&#xff1b; 如果主节点宕机了&#xff0c; 程序会中断操作。 而Rabbitmq集群&#xff0c;会马上让没有宕机的节点参选&#xff0c;选出新的主要节点。 程序重试…

postgresql分区表相关问题处理

1.使用pg_cron按日创建分区表&#xff0c;会出现所在数据库对应用户权限不足的问题。 原因是pg_cron运行在postgres数据库中&#xff0c;是用superuser进行执行的&#xff0c;对应的分区表的owner为postgres&#xff0c;所以需要单独授权对表的所有操作权限。不知道直接改变ow…

网络数据链路层以太网协议

网络数据链路层以太网协议 1. 以太网协议介绍 以太网是一个数据链路层协议&#xff0c;数据链路层的作用是用于两个设备&#xff08;同一种数据链路节点&#xff09;之间进行传递。 以太网不是一种具体的网络&#xff0c;而是一种网络技术标准&#xff0c;既包含了数据链路层…

Kotlin 循环语句详解

文章目录 循环类别for-in 循环区间整数区间示例1&#xff1a;正向遍历示例2&#xff1a;反向遍历 示例1&#xff1a;遍历数组示例2&#xff1a;遍历区间示例3&#xff1a;遍历字符串示例4&#xff1a;带索引遍历 while 循环示例&#xff1a;计算阶乘 do-while 循环示例&#xf…