先说结论,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到底能否解决幻读问题相关推荐

  1. mysql中a b为什么是假_[灵魂拷问]MySQL面试高频问题(工程师方向)

    前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉水. 前一阵系统的学习了一下MySQL,也有一些实际操作经验,偶然看到一篇和MySQL相关的面 ...

  2. mysql 一个字段下保存多张张照片_如何用MYSQL数据库创建表格,小白一定要进来看看

    "在这个时代,太慢你是要被淘汰的.可问题是你怎样能快起来." "把最基础的环节打通之后,再有新的知识就能在这个基础上生长." 上面这两句话是我在成甲的书里读到的 ...

  3. 灵魂拷问,MySQL到底能否解决幻读问题

    先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...

  4. mysql 解决了幻影读_MySQL到底能否解决幻读问题

    先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...

  5. MySQL数据库场景下的NVMe SSD应用与优化

    在DB-Engines Ranking的榜单上,Oracle.MySQL和SQL Server前三的地位仍是不可撼动的.作为一家专注于NVMe SSD设计研发的厂商,Memblaze关注的是NVMe ...

  6. [灵魂拷问]MySQL面试高频100问(工程师方向)

    前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉水. 前一阵系统的学习了一下MySQL,也有一些实际操作经验,偶然看到一篇和MySQL相关的面 ...

  7. [灵魂拷问]MySQL面试高频一百问

     作者:呼延十 链接:https://juejin.im/post/5d351303f265da1bd30596f9 前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多, ...

  8. mysql的配置中主机地址怎么填_连接到mysql主机数据库配置命令-mysql主机地址

    连接到mysql主机数据库配置命令-mysql主机地址 2019/04/01 作者: 互盟股份 mysql虚拟主机的配置方法是怎样的?要知道,大部分选择虚拟主机的人最常用到的是Windows系统,而在 ...

  9. mysql root用户可以同时几个人连接_重学MySQL系列(四):10分钟快速掌握MySQL用户与权限管理

    在这篇文章中,我们来聊聊怎么管理MySQL的用户及如何为不同用户分配不同的管理权限,其实,在日常使用MySQL的过程中,这部分的工作是由DBA(数据管理员)来完成的. 而我们作为一般的开发人员,只要拿 ...

最新文章

  1. 无线节能信标调试说明-2021-3-3
  2. mongoDB - 日常操作四
  3. PMCAFF|盘点2016最值得突击的七大海外市场:最后一年窗口期,不出海就出局!...
  4. ElementUI中实现表单刷新重置,保存在全局方法中
  5. Scala里List(1,2,3)和(1,2,3)的区别
  6. S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)
  7. CentOS 上snmp的安装和配置
  8. [Linux 性能检测工具]DF
  9. python hook_五分钟内用Python实现GitHook
  10. Spring MVC+Stomp+Security+H2 Jetty 1
  11. UML的简单介绍和画法
  12. 初识Java 之软件下载与安装配置
  13. STM32+WIFI模块(EMW3080)使用MQTT协议链接阿里云服务器
  14. 【马克思主义基本原理】--导论
  15. 搜狗输入法5.0正式版发布 首创云计算输入
  16. 计算机术语IP,什么是ip?网络ip和网络用语IP的含义!
  17. PMP证书的含金量高吗?值得考吗?
  18. [LBS学习笔记3]redis geo地理位置查询分析
  19. 智慧政务云平台建设方案案例与基础架构
  20. 通过mac地址找设备的IP地址

热门文章

  1. 10分钟快速充电,WPG闪电充你了解吗?
  2. 遗传算法:最全的序列整数编码交叉算子 permutation encoding integer encoding crossover operator
  3. docker通过模板创建镜像以及容器、仓库和数据管理
  4. 建站技术是一锤子买卖,而建站服务则是长久性的共赢吗?
  5. git提交出现Another git process seems to be running in this repositorye.g. an editor opened by ‘git commi
  6. 背上“租金贷”包袱,青客公寓还能“跑”吗?
  7. Python爬虫-暨大考研报录比
  8. 径向模糊shader
  9. 嵌入式系统编程之内存操作的注意事项
  10. Go微服务实战1:为什么是go