MySQL45讲 第二十讲 幻读是什么,幻读有什么问题?

文章目录

  • MySQL45讲 第二十讲 幻读是什么,幻读有什么问题?
    • 一、幻读的定义
    • 二、幻读带来的问题
      • (一)语义问题
      • (二)数据一致性问题
    • 三、InnoDB 解决幻读的方法
    • 四、总结

MySQL45讲 第二十讲 幻读是什么,幻读有什么问题?

在数据库事务处理的复杂世界里,幻读是一个不容忽视的重要概念。它不仅关乎数据的一致性,还与事务隔离性紧密相连。今天,我们就一同深入探讨幻读的奥秘,解析其定义、所引发的问题,以及 InnoDB 是如何巧妙解决这一难题的。


一、幻读的定义

幻读究竟是什么呢?简单来说,在可重复读隔离级别下,当一个事务对同一个范围进行前后两次查询时,后一次查询竟然发现了前一次查询中未曾出现的行。这就好比在一个神秘的魔法世界里,数据会 “凭空” 出现或消失,让人捉摸不透。

假设有一个名为t的表,其结构如下:

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

在这个表中,除了主键id外,还有一个索引c,并且已经初始化插入了 6 行数据。

现在,我们考虑这样一个事务操作序列。在事务 A 中,执行了三次查询语句select * from t where d = 5 for update,分别标记为 Q1、Q2 和 Q3。根据事务可见性规则,这些查询使用了当前读,应该能够读到所有已提交记录的最新值。

在这里插入图片描述

  • Q1 查询时,表中只有id = 5这一行满足d = 5的条件,所以 Q1 只返回了这一行。
  • 在 T2 时刻,事务 B 执行了update t set d = 5 where id = 0,将id = 0这一行的d值修改为 5。此时,事务 A 的 Q2 查询就会看到id = 0id = 5这两行,因为事务 B 的修改已经提交,Q2 需要读到最新值。
  • 接着,在 T4 时刻,事务 C 插入了一行(1,1,5)。当事务 A 执行 Q3 查询时,就会看到id = 0id = 1id = 5这三行。

这里,Q3 读到id = 1这一行的现象就是幻读。需要注意的是,在可重复读隔离级别下,普通查询是快照读,不会看到其他事务插入的数据,幻读仅在当前读下才会出现。而且,幻读特指新插入的行,像事务 B 的修改结果被事务 A 之后的查询用当前读看到,并不属于幻读范畴。


二、幻读带来的问题

(一)语义问题

从语义角度来看,幻读会导致事务的加锁声明失去意义。

就像事务 A 在 T1 时刻声明要锁住所有d = 5的行,禁止其他事务进行读写操作。然而,由于幻读的存在,事务 B 可以修改id = 0这一行的d值为 5,事务 C 还能插入新的(1,1,5)行,这显然破坏了事务 A 的加锁语义。

我们通过一个详细的场景来进一步说明。假设事务 B 和事务 C 在执行修改和插入操作时,还分别执行了其他相关操作:

session Asession Bsession C
T1begin; select * from t where d = 5 for update; / * Q1 * /
T2update t set d = 5 where id = 0; update t set c = 5 where id = 0;

T3select * from t where d = 5 for update; / * Q2 * /
T4insert into t values(1,1,5); update t set c = 5 where id = 1;
T5select * from t where d = 5 for update; / * Q3 * /
T6commit;

事务 B 的第二条语句update t set c = 5 where id = 0,语义是修改id = 0d = 5这一行的c值为 5。但由于事务 A 在 T1 时刻只给id = 5这一行加了行锁,没有锁住id = 0这行,所以事务 B 在 T2 时刻可以执行这两条更新语句,这就与事务 A 中 Q1 语句要锁住所有d = 5的行的语义相违背。同样,事务 C 对id = 1这一行的修改也破坏了 Q1 的加锁声明。

(二)数据一致性问题

幻读还会引发数据一致性问题,这涉及到数据库内部数据状态以及数据和日志在逻辑上的一致性。

我们在事务 A 的 T1 时刻添加一个更新语句update t set d = 100 where d = 5,然后分析整个执行序列完成后的情况。

经过 T1 时刻,id = 5这一行变成(5,5,100),最终在 T6 时刻提交。T2 时刻,id = 0这一行变为(0,5,5);T4 时刻,表中新增了一行(1,5,5)。此时,数据库中的数据看起来似乎没有问题。

但是,当我们查看 binlog 中的内容时,就会发现问题。T2 时刻,事务 B 提交,写入了两条语句;T4 时刻,事务 C 提交,写入了两条语句;T6 时刻,事务 A 提交,写入了update t set d = 100 where d = 5这条语句。按照 binlog 的执行顺序,最终id = 0id = 1这两行的结果会变成(0,5,100)(1,5,100),与数据库中的实际结果不一致。

这种数据不一致的情况非常严重,它可能导致数据的错乱,影响系统的正常运行。例如,在一个电商系统中,如果出现这种数据不一致,可能会导致订单信息错误、库存数量不准确等问题,给企业带来巨大的损失。


三、InnoDB 解决幻读的方法

为了解决幻读问题,InnoDB 引入了一种新的锁机制 —— 间隙锁(Gap Lock)。间隙锁,顾名思义,就是锁住两个值之间的空隙。

以我们之前的表t为例,初始化插入 6 个记录后,会产生 7 个间隙,分别是(-∞,0)(0,5)(5,10)(10,15)(15,20)(20,25)(25,+∞)。当执行select * from t where d = 5 for update时,InnoDB 不仅会给已有的 6 个记录加上行锁,还会同时给这 7 个间隙加上间隙锁,确保无法再插入新的记录。

间隙锁和行锁合称 Next - Key Lock,每个 Next - Key Lock 是前开后闭区间。例如,当使用select * from t for update要锁住整个表所有记录时,就会形成 7 个 Next - Key Lock,分别是(-∞,0](0,5](5,10](10,15](15,20](20, 25](25, +supremum]。这里的+supremum是 InnoDB 为每个索引添加的一个不存在的最大值,用于满足前开后闭区间的定义。

间隙锁的引入虽然解决了幻读问题,但也带来了一些新的困扰。由于间隙锁会锁定更大的范围,可能会导致并发度下降,甚至引发死锁。

例如,考虑这样一个业务逻辑:任意锁住一行,如果该行不存在则插入,如果存在则更新其数据。

在这里插入图片描述

在并发情况下,可能会出现死锁现象。假设两个事务 A 和 B 都试图执行这个逻辑,且都要操作id = 9这一行(假设该行初始不存在)

  • 事务 A 先执行select * from t where id = 9 for update,由于id = 9不存在,会加上间隙锁(5,10)
  • 接着事务 B 也执行select * from t where id = 9 for update,同样加上间隙锁(5,10),此时间隙锁之间不冲突,事务 B 的语句可以执行成功。
  • 然后事务 B 试图插入一行(9,9,9),但被事务 A 的间隙锁挡住,进入等待状态。
  • 而事务 A 此时也试图插入(9,9,9),同样被事务 B 的间隙锁挡住,两个事务就进入了互相等待的死锁状态。

当然,InnoDB 的死锁检测机制会及时发现这种死锁关系,并让其中一个事务的插入语句报错返回,以避免系统长时间阻塞。

如果想要避免间隙锁带来的这些问题,还有一种配置选择,就是将隔离级别设置为读提交。在这种隔离级别下,就没有间隙锁了,但需要将 binlog 格式设置为 row,以解决可能出现的数据和日志不一致问题。不过,这种配置是否合理,需要根据具体的业务场景来分析。如果业务不需要可重复读的保证,读提交隔离级别下操作数据的锁范围更小,可能是一个合理的选择。但如果盲目跟风使用这种配置,而没有考虑业务实际需求,可能会在后续的运行中出现各种问题。


四、总结

  • 幻读在数据库事务处理中是一个复杂而关键的问题,它对数据的一致性和事务的隔离性有着重要影响。通过本文的详细分析,我们了解到幻读的定义、产生的问题以及 InnoDB 的解决方案。

  • 在实际应用中,我们需要深入理解这些概念,根据业务需求合理选择事务隔离级别和配置。如果对间隙锁等机制理解不足,可能会导致生产库上出现死锁等问题,影响系统的性能和稳定性。希望本文能够帮助读者更好地掌握幻读相关知识,在数据库设计和开发中做出明智的决策,构建出更加可靠、高效的数据库应用系统。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web与网络编程

使用HTTP协议访问Web 通过发送请求获取服务器资源的Web浏览器等,被成为客户端(client)。 Web使用一种名为HTTP(超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。 可以说,Web时建立在HTTP协议上通信的。 网络基础T…

深入理解接口测试:实用指南与最佳实践5.0(五)

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…

2024游戏陪玩app源码的功能介绍/线上陪玩交友上线即可运营软件平台源码搭建流程

一个完整的陪玩交友系统从概念到实现再到维护的全过程得以清晰展现。每一步都需要团队的紧密协作与细致规划,以确保系统既满足用户需求,又具备良好的稳定性和可扩展性。 基础框架 移动端开发框架:如uniapp,它支持多平台开发&…

预测AI如何提升销售绩效管理:五大方式

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

修改数据库和表的字符集

1、修改数据库字符集 mysql> show CHARACTER SET; 查看所有字符集 mysql> show create database wordpress; 查看数据库wordpress当前字符集mysql> alter database wordpress character set gbk; 将数据库wordpress字符集改为gb…

DB-GPT系列(四):DB-GPT六大基础应用场景part1

一、基础问答 进入DB-GPT后,再在线对话默认的基础功能就是对话功能。这里我们可以和使用通义千问、文心一言等在线大模型类似的方法, 来和DB-GPT进行对话。 但是值得注意的是,DB-GPT的输出结果是在内置提示词基础之上进行的回答&#xff0c…

海量数据面试题

目录 前言 什么是海量数据 一、利用位图解决 二、利用布隆过滤器解决 三、利用哈希切割解决 前言 在大数据时代,海量数据处理已成为技术领域中的一项重要课题。无论是企业级应用、互联网平台,还是人工智能和机器学习的实现,都离不开对大规…

操作系统实验:在linux下用c语言模拟进程调度算法程序

文章目录 1、实验内容2、实验结果及分析3、如何在linux下编写并执行c语言程序以及实验源代码gcc -o test test.c1、实验内容 1)用C语言编程实现对N个进程采用某种进程调度算法(如动态优先权调度算法、先来先服务算法、短进程优先算法、时间片轮转调度算法)调度执行的模拟。…

前端开发迈向全栈之路:规划与技能

一、前端开发与全栈开发的差异 前端开发主要负责构建和实现网页、Web 应用程序和移动应用的用户界面。其工作重点在于网页设计和布局,使用 HTML 和 CSS 技术定义页面的结构、样式和布局,同时运用前端框架和库如 React、Angular 或 Vue.js 等构建交互式和…

GOLANG+VUE后台管理系统

1.截图 2.后端工程截图 3.前端工程截图

中文书籍对《人月神话》的引用(161-210本):微软的秘密

中文书籍对《人月神话》的引用(第001到160本)>> 《人月神话》于1975年出版,1995年出二十周年版。自出版以来,该书被大量的书籍和文章引用,直到现在热潮不退。 2023年,清华大学出版社推出《人月神话》…

IO流(五):字节流-输入流(Inpustream)、输出流(OutputStream)--使用场景、弊端、注意事项、代码演示。

目录 1、什么是字节流? 2、字节输入流--FileInputStream 2.1 int read()方式代码演示以及注释 2.1.1 读取一个字节 2.1.2 将整个文件挨个字节读取并打印演示 2.2 int read(byte[] buffer)方式代码演示以及注释 2.2 .1 一次读取3字节演示 2.2.2 一次性读取全…

直流保护电路设计及保护器件参数说明和选型

在工控产品设计中时常会涉及到电源保护的电路设计的问题,在深圳瑞隆源电子给出的参考电路来切入主题,对气体放电管、压敏电阻和TVS这三类保护器件的参数及选型进行详细说明,以达到深刻理解的目的。 图1 直流保护电路 举例说明,若…

FastGPT部署通义千问Qwen和智谱glm模型|OneAPI配置免费的第三方API

继这篇博客之后 从零开始FastGPT本地部署|Windows 有同学问,不想在多个平台申请API-Key,不好管理且要付费,有木有白嫖方案呀? 答:有啊。用硅基流动。 注册方法看这篇 【1024送福利】硅基流动送2000万token啦&#xff0…

机器学习day2-特征工程

四.特征工程 1.概念 一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程 将任意数据(文本或图像等)转换为数字特征,对特征进行相关的处理 步骤:1.特征提取;2.无量纲化(预处理&#xf…

sql数据库-排序查询-DQL

目录 语法 排序方式 举例 将表按年龄从小到大排序 将表按年龄从大到小排序 ​编辑 多重排序 将表按年龄升序,年龄相同按入职时间降序 语法 select * from 表名 order by 字段名1 排序方式1,字段2 排序方式2; 排序方式 升序:ASC&…

响应“一机两用”政策 落实政务外网安全

在数字化时代,政务办公外网安全的重要性日益凸显,特别是在“一机两用”的背景下,即同一台终端既要处理政务内网的数据,又要访问互联网,这对网络安全提出了更高的要求。深信达SPN安全上网方案,即反向沙箱技术…

测试实项中的偶必现难测bug--互斥逻辑异常

问题: 今天线上出了一个很奇怪的问题,看现象和接口是因为数据问题导致app模块奔溃 初步排查数据恢复后还是出现了数据重复的问题,查看后台实际只有一条数据,但是显示在app却出现了两条一模一样的置顶数据 排查: 1、顺着这个逻辑,我们准备在预发复现这个场景,先是cop…

Burpsuite的安装使用说明——【渗透工具介绍与使用】

# 前记 **工欲善其事必先利其器,本系列先介绍一些常见的安全工具的安装与使用** 该文章介绍的是Burpsuite的安装使用说明 > 🍀 作者简介 > 小菜鸡罢了,研究过漏洞、扫过端口、写过脚本,迷恋着CTF,脑袋里充满了各…

如何在 WordPress 中轻松强制所有用户退出登录

作为一名长期管理 WordPress 网站的站长,我深知维护网站安全性的重要性。尤其是在面对会员网站或付费内容平台时,确保所有用户的登录状态是最新的,是维持网站正常运营的关键之一。今天,我就分享一下如何通过简单的步骤&#xff0c…