mysql什么场景下要防止幻读_灵魂拷问,MySQL到底能否解决幻读问题
先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的。
方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作;2.给涉及到的行两端加间隙锁(Gap Lock)防止新增行写入;从而解决了幻读问题。
下面,让我带大家从原理出发,一起来搞懂MySQL并发问题 -- “幻读”。如果有好的看法,咱们评论见吧。
小伙伴想精准查找自己想看的MySQL文章?喏 →MySQL专栏目录 | 点击这里
目录
什么是幻读
要知道什么是幻读,首先要知道以下四点:
一、幻读定义
幻读是指在同一个事务中,存在前后两次查询同一个范围的数据,但是第二次查询却看到了第一次查询没看到的行,一般情况下特指事务执行中新增的其他行。
二、幻读示例
测试表数据:
mysql> select * from LOL;
+----+--------------+--------------+-------+
| id | hero_title | hero_name | price |
+----+--------------+--------------+-------+
| 1 | 刀锋之影 | 泰隆 | 6300 |
| 2 | 迅捷斥候 | 提莫 | 6300 |
| 3 | 光辉女郎 | 拉克丝 | 1350 |
| 4 | 发条魔灵 | 奥莉安娜 | 6300 |
| 5 | 至高之拳 | 李青 | 6300 |
| 6 | 无极剑圣 | 易 | 450 |
| 7 | 疾风剑豪 | 亚索 | 6300 |
+----+--------------+--------------+-------+
7 rows in set (0.00 sec)
下面是一个出现幻读情况示例,我们一起来看一下;
时刻T
Session A
Session B
Session C
T1
begin;
-- Query1
select * from LOL where price=450 for update;
Result:(6,'无极剑圣',450)
T2
update LOL set price=450 where hero_title = '疾风剑豪'
T3
-- Query2
select * from LOL where price=450 for update;
Result:(6,'无极剑圣',450),(7,'疾风剑豪',450)
T4
insert into LOL values(10,'雪人骑士','努努','450')
T5
-- Query3
select * from LOL where price=450 for update;
Result:(6,'无极剑圣',450),(7,'疾风剑豪',450),(10,'雪人骑士',450)
T6
commit;
可以看到,session A 里执行了三次查询,分别是 Q1、Q2 和 Q3。它们的 SQL 语句相同,都是 select * from LOL where price=450 for update。这个语句的意思你应该很清楚了,查所有 price=450 的行,而且使用的是当前读,并且加上写锁。现在,我们来看一下这三条 SQL 语句,分别会返回什么结果。
Q1 只返回 "无极剑圣" 这一行;
在 T2 时刻,session B 把 "疾风剑豪" 这一行的 price 值改成了 450,因此 T3 时刻 Q2 查出来的是 "无极剑圣" 和 "疾风剑豪" 这两行;
在 T4 时刻,session C 又插入一行 (10,'雪人骑士','努努','450'),因此 T5 时刻 Q3 查出来 price = 450 的是"无极剑圣" 、"疾风剑豪" 和 "雪人骑士"这三行。
其中,Q3 读到(10,'雪人骑士',450) 这一行的现象,被称为“幻读”。也就是说,幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
三、幻读出现的场景
幻读出现在可重复读(RR)隔离级别下,普通的SELECT查询就是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。(当前读会生成行锁,但行锁只能锁定存在的行,针对新插入的操作没有限定)
上面 session B 的修改结果,被 session A 之后的 select 语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。
因为这三个查询都是加了 for update,都是当前读。而当前读的规则,就是要能读到所有已经提交的记录的最新值。并且,session B 和 sessionC 的两条语句,执行后就会提交,所以 Q2 和 Q3 就是应该看到这两个事务的操作效果,而且也看到了,这跟事务的可见性规则并不矛盾。
四、解决幻读问题的必要性
在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。
如何解决幻读
如果你看到了这篇文章,那么我会默认你了解了脏读 、不可重复读与可重复读。如果还不清楚可以先参阅《上个厕所的功夫,搞懂MySQL事务隔离级别》
场景如上,场景隔离级别为RR,当前读。
一、原理解读
那么幻读能仅通过行锁解决么?答案是否定的,如上面示例,首先说明一下,select xx for update(当前读)是将所有条件涉及到的(符合where条件)行加上行锁。但是,就算我在select xx for update 事务开启时将所有的行都加上行锁。那么也锁不住Session C新增的行,因为在我给数据加锁的时刻,压根就还没有新增的那行,自然也不会给新增行加上锁。
所以要解决幻读,就必须得解决新增行的问题。
现在你应该明白了,产生幻读的原因是:行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。顾名思义,间隙锁,锁的就是两个值之间的空隙。比如文章开头的表 LOL,初始化插入了 7 个记录,这就产生了 8 个间隙。
二、next-key lock
这样,当你执行 select * from LOL where hero_title = '疾风剑豪' for update 的时候,就不止是给数据库中已有的 7 个记录加上了行锁,还同时加了 8 个间隙锁。这样就确保了无法再插入新的记录,也就是Session C在T4新增(10,'雪人骑士','努努','450') 行时,由于ID大于7,被间隙锁(7,+∞)锁住。
在一行行扫描的过程中,不仅将给行加上了行锁,还给行两边的空隙,也加上了间隙锁。MySQL将行锁 + 间隙锁组合统称为 next-key lock,通过 next-key lock 解决了幻读问题。
注意
next-key lock的确是解决了幻读问题,但是next-key lock在并发情况下也经常会造成死锁。死锁检测和处理也会花费时间,一定程度上影响到并发量。
参考资料
《高性能MySQL》
《丁奇MySQL实战45讲》
一张照片的故事
或许京剧自己都没想到
清末的洋人,民国的战火都没能毁了它
最后居然是衰落在中国人自己的手里
本文同步分享在 博客“_陈哈哈”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
mysql什么场景下要防止幻读_灵魂拷问,MySQL到底能否解决幻读问题相关推荐
- mysql中a b为什么是假_[灵魂拷问]MySQL面试高频问题(工程师方向)
前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉水. 前一阵系统的学习了一下MySQL,也有一些实际操作经验,偶然看到一篇和MySQL相关的面 ...
- mysql 一个字段下保存多张张照片_如何用MYSQL数据库创建表格,小白一定要进来看看
"在这个时代,太慢你是要被淘汰的.可问题是你怎样能快起来." "把最基础的环节打通之后,再有新的知识就能在这个基础上生长." 上面这两句话是我在成甲的书里读到的 ...
- 灵魂拷问,MySQL到底能否解决幻读问题
先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...
- mysql 解决了幻影读_MySQL到底能否解决幻读问题
先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...
- MySQL数据库场景下的NVMe SSD应用与优化
在DB-Engines Ranking的榜单上,Oracle.MySQL和SQL Server前三的地位仍是不可撼动的.作为一家专注于NVMe SSD设计研发的厂商,Memblaze关注的是NVMe ...
- [灵魂拷问]MySQL面试高频100问(工程师方向)
前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉水. 前一阵系统的学习了一下MySQL,也有一些实际操作经验,偶然看到一篇和MySQL相关的面 ...
- [灵魂拷问]MySQL面试高频一百问
作者:呼延十 链接:https://juejin.im/post/5d351303f265da1bd30596f9 前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多, ...
- mysql的配置中主机地址怎么填_连接到mysql主机数据库配置命令-mysql主机地址
连接到mysql主机数据库配置命令-mysql主机地址 2019/04/01 作者: 互盟股份 mysql虚拟主机的配置方法是怎样的?要知道,大部分选择虚拟主机的人最常用到的是Windows系统,而在 ...
- mysql root用户可以同时几个人连接_重学MySQL系列(四):10分钟快速掌握MySQL用户与权限管理
在这篇文章中,我们来聊聊怎么管理MySQL的用户及如何为不同用户分配不同的管理权限,其实,在日常使用MySQL的过程中,这部分的工作是由DBA(数据管理员)来完成的. 而我们作为一般的开发人员,只要拿 ...
最新文章
- 无线节能信标调试说明-2021-3-3
- mongoDB - 日常操作四
- PMCAFF|盘点2016最值得突击的七大海外市场:最后一年窗口期,不出海就出局!...
- ElementUI中实现表单刷新重置,保存在全局方法中
- Scala里List(1,2,3)和(1,2,3)的区别
- S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)
- CentOS 上snmp的安装和配置
- [Linux 性能检测工具]DF
- python hook_五分钟内用Python实现GitHook
- Spring MVC+Stomp+Security+H2 Jetty 1
- UML的简单介绍和画法
- 初识Java 之软件下载与安装配置
- STM32+WIFI模块(EMW3080)使用MQTT协议链接阿里云服务器
- 【马克思主义基本原理】--导论
- 搜狗输入法5.0正式版发布 首创云计算输入
- 计算机术语IP,什么是ip?网络ip和网络用语IP的含义!
- PMP证书的含金量高吗?值得考吗?
- [LBS学习笔记3]redis geo地理位置查询分析
- 智慧政务云平台建设方案案例与基础架构
- 通过mac地址找设备的IP地址
热门文章
- 10分钟快速充电,WPG闪电充你了解吗?
- 遗传算法:最全的序列整数编码交叉算子 permutation encoding integer encoding crossover operator
- docker通过模板创建镜像以及容器、仓库和数据管理
- 建站技术是一锤子买卖,而建站服务则是长久性的共赢吗?
- git提交出现Another git process seems to be running in this repositorye.g. an editor opened by ‘git commi
- 背上“租金贷”包袱,青客公寓还能“跑”吗?
- Python爬虫-暨大考研报录比
- 径向模糊shader
- 嵌入式系统编程之内存操作的注意事项
- Go微服务实战1:为什么是go