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

简聊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的数据时就会被阻塞。

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

相关文章:

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

在MySQL数据库中&#xff0c;事务的幻读和虚读问题是并发控制中的关键挑战。以下是针对这两个问题的解决方案及原理说明&#xff0c;并附上相关示例。 一、幻读问题及其解决方案 幻读问题的定义 幻读是指一个事务在前后两次查询同一个范围的时候&#xff0c;后一次查询看到了…...

【搭建JavaEE】(2)Tomcat安装配置和第一个JavaEE程序

Tomcat–容器(Container) 下载 Apache Tomcat - Welcome! 下载完成 请求/响应 结构 测试 查看Jdk版本 改端口号localhost8080–>8099 学学人家以后牛逼了可以用自己名字当文件夹名 配置端口8099 找到server文件 用记事本打开 再打开另一个logging文件 ”乱码解决“步骤&…...

【Qt】01-了解QT

踏入QT的殿堂之路 前言一、创建工程文件1.1 步骤介绍1.2 编译介绍方法1、方法2、编译成功 二、了解框架2.1 main.cpp2.2 .Pro文件2.2.1 注释需要打井号。2.2.2 F1带你进入帮助模式2.2.3 build文件 2.3 构造函数 三、编写工程3.1 main代码3.2 结果展示 四、指定父对象4.1 main代…...

websocket股票行情接口

股票行情区别 交易所出来的数据&#xff0c;不管通过什么渠道&#xff0c;延时一般都不会差太远&#xff0c;估计一般也就几十ms的差别。 但是如果是通过http轮询&#xff0c;不太可能几十ms全部轮询一次。所以&#xff0c;做量化的话&#xff0c;用http协议是最次的选择。 …...

朴素贝叶斯分类器

目录 一、生成模型&#xff08;学习&#xff09;&#xff08;Generative Model&#xff09; vs 判别模型&#xff08;学习&#xff09;&#xff08;Discriminative Model&#xff09; 1、官方说明 2、通俗理解 3、举例 二、生成学习算法 1、数学符号说明 2、贝叶斯公式 …...

智能化植物病害检测:使用深度学习与图像识别技术的应用

植物病害一直是农业生产中亟待解决的问题&#xff0c;它不仅会影响作物的产量和质量&#xff0c;还可能威胁到生态环境的稳定。随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;尤其是深度学习和图像识别技术的应用&#xff0c;智能化植物病害检测已经成为一…...

vim基本命令(vi、工作模式、普通模式、插入模式、可视模式、命令行模式、复制、粘贴、插入、删除、查找、替换)

1. Vim的作用 1.1. 文本编辑 1.1.1. 基础文本编辑功能 Vim是一个功能强大的文本编辑器&#xff0c;它可以用来创建、修改和保存各种文本文件。无论是编写简单的文本笔记&#xff0c;还是复杂的代码文件&#xff0c;Vim都能胜任。例如&#xff0c;我们可以用它来编写Python脚…...

Qt 自动根据编译的dll或exe 将相关dll文件复制到目标文件夹

Qt 自动根据编译的dll或exe 将相关dll文件复制到目标文件夹 如果你在使用 windeployqt 时遇到错误 “windeployqt 不是内部或外部命令”&#xff0c;说明你的命令行环境没有正确配置 Qt 工具路径。windeployqt 是 Qt 工具的一部分&#xff0c;它用于自动将所有必要的 Qt 库和插…...

探索新能源汽车“芯”动力:AUTO TECH China 2025广州国际新能源汽车功率半导体技术展盛况空前

广州&#xff0c;2025年11月20日‌ —— 在全球新能源车市场蓬勃发展的背景下&#xff0c;AUTO TECH China 2025 广州国际新能源汽车功率半导体技术展览会将于2025年11月20-22日在广州保利世贸博览馆盛大开幕。此次展会作为亚洲领先的车用功率半导体技术专业盛会&#xff0c;本…...

Kafka权威指南(第2版)读书笔记

目录 Kafka生产者——向Kafka写入数据生产者概览创建Kafka生产者bootstrap.serverskey.serializervalue.serializer 发送消息到Kafka同步发送消息 Kafka生产者——向Kafka写入数据 不管是把Kafka作为消息队列、消息总线还是数据存储平台&#xff0c;总是需要一个可以往Kafka写…...

WORD转PDF脚本文件

1、在桌面新建一个文本文件&#xff0c;把下列代码复制到文本文件中。 On Error Resume Next Const wdExportFormatPDF 17 Set oWord WScript.CreateObject("Word.Application") Set fso WScript.CreateObject("Scripting.Filesystemobject") Set fdsf…...

electron 打包后的 exe 文件,运行后是空白窗口

一、代码相关问题 1. 页面加载失败 1.1 原因 在 Electron 应用中&#xff0c;若loadFile或loadURL方法指定的页面路径或 URL 错误&#xff0c;就无法正确加载页面&#xff0c;导致窗口空白。 1.2. 解决 仔细检查loadFile或loadURL方法中传入的路径或 URL 是否正确&#xf…...

数据库重连 - 方案

要解决 SQL Server 连接失效后导致的错误问题,可以考虑以下几种解决方案: 1. 连接池机制: 通过实现一个连接池,确保连接失效后可以重新建立连接,而不会直接导致整个程序出错。连接池可以帮助在连接中断时自动恢复连接,而不必每次手动重连。 例如,可以通过以下方式定期…...

从 PostgreSQL 中挽救损坏的表

~/tmp-dir.dab4fd85-8b47-4d9a-b15c-18312ef61075 pg_dump -U postgres -h locathost www_p1 > wow_p1.sqlpg_dump&#xff1a;错误&#xff1a;转储表 “page_views” 的内容失败&#xff1a;PQgetResult() 失败。pg_dump&#xff1a;详细信息&#xff1a;来自服务器的错误…...

【Vue3 入门到实战】1. 创建Vue3工程

目录 ​编辑 1. 学习目标 2. 环境准备与初始化 3. 项目文件结构 4. 写一个简单的效果 5. 总结 1. 学习目标 (1) 掌握如何创建vue3项目。 (2) 了解项目中的文件的作用。 (3) 编辑App.vue文件&#xff0c;并写一个简单的效果。 2. 环境准备与初始化 (1) 安装 Node.js 和 …...

rtthread学习笔记系列(10/11) -- 系统定时器

文章目录 10. 系统定时器10.1 跳跃表[定时器跳表 (Skip List) 算法](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/timer/timer?id定时器跳表-skip-list-算法) 10.2 硬件定时器10.2.1 初始化&&删除10.2.2 sta…...

mock服务-通过json定义接口自动实现mock服务

go-mock介绍 不管在前端还是后端开发过程中&#xff0c;当我们需要联调其他服务的接口&#xff0c;而这个服务还没法提供调用时&#xff0c;那我们就要用到mock服务&#xff0c;自己按接口文档定义一个临时接口返回指定数据&#xff0c;以供本地开发联调测试。 怎么快速启动一…...

像JSONDecodeError: Extra data: line 2 column 1 (char 134)这样的问题怎么解决

问题介绍 今天处理返回的 JSON 的时候&#xff0c;出现了下面这样的问题&#xff1a; 处理这种问题的时候&#xff0c;首先你要看一下当前的字符串格式是啥样的&#xff0c;比如我查看后发现是下面这样的&#xff1a; 会发现这个字符串中间没有逗号&#xff0c;也就是此时的J…...

C#版 软件开发6大原则与23种设计模式

开发原则和设计模式一直是软件开发中的圣经, 但是这仅仅适用于中大型的项目开发, 在小型项目的开发中, 这些规则会降低你的开发效率, 使你的工程变得繁杂. 所以只有适合你的才是最好的. 设计模式六大原则1. 单一职责原则&#xff08;Single Responsibility Principle&#xff0…...

java8 springboot 集成javaFx 实现一个客户端程序

1. 先创建一个springboot 程序(此步骤不做流程展示) 2. 更改springboot的版本依赖和导入所需依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.7</versio…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...

VSCode 没有添加Windows右键菜单

关键字&#xff1a;VSCode&#xff1b;Windows右键菜单&#xff1b;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意&#xff0c;实际使用的时候发现 VSCode 在 Windows 菜单栏…...

Python打卡训练营学习记录Day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

C++参数传递 a与a的区别

在 C 中&#xff0c;&a&#xff08;引用&#xff09;和 a&#xff08;值传递&#xff09; 的关键区别在于 参数如何传递给函数&#xff0c;以及由此引发的 性能、语义和安全问题。 最核心的在于你想不想传入的参数被改变&#xff0c;如果想&#xff0c;就用参数传递&#…...

Asp.net Core 通过依赖注入的方式获取用户

思路&#xff1a;Web项目中&#xff0c;需要根据当前登陆的用户&#xff0c;查询当前用户所属的数据、添加并标识对象等。根据请求头Authorization 中token&#xff0c;获取Redis中存储的用户对象。 本做法需要完成 基于StackExchange.Redis 配置&#xff0c;参考&#xff1a;…...