面试官:MySql在Repeatable Read下面是否会有幻读出现?
目录
▎事务隔离级别定义
了解:三种读现象(Read phenomena)
▎幻读:在可重复读级别下的 “特殊场景”
所以:MySQL的 InnoDB引擎在RR级别下到底能否解决幻读?
RR级别下InnoDB解决常规幻读的原理
▎总结
前言:在解决这个问题之前, 我们先复习一下关于事务隔离的定义。
▎事务隔离级别定义
数据库事务的ACID四个属性中,隔离性是一个限制最宽松的。为了获取更高的隔离等级,DBMS通常使用 锁机制 或者 多版本并发控制 机制。 应用软件也需要额外的逻辑来使其正常工作。
很多数据库管理系统(DBMS)定义了不同的 “事务隔离等级” 来控制锁的程度。大多数据库系统中,都不会选择最高等级: 可串行化 隔离级别,从而减少锁的开销。
✰ 低一级的隔离级别要求更多的限制,高一级的级别提供更强的隔离性。
更高的隔离级别会增加死锁发生的几率,需要编程过程中去避免。
SQL定义的标准隔离级别如下
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read Uncommitted (读未提交) |
存在 | 存在 | 存在 |
Read Committed (读已提交) |
- | 存在 | 存在 |
Repeatable Read (可重复读)默认 |
- | - | 存在 |
Serializable (可串行化) |
- | - | - |
1. 读未提交(Read Uncommitted)
最低的隔离级别。允许“脏读”(dirty reads),事务可以看到其他事务“尚未提交”的修改。
2. 读已提交(Read Committed)
基于锁机制并发控制的DBMS,会对选定对象的写锁一直保持到事务结束,但是读锁在select操作完成后马上释放(因此“不可重复读”现象可能会发生)。
3. 可重复读(Repeatable Read)
基于锁机制并发控制的DBMS,会对选定对象的读锁 和 写锁一直保持到事务结束,但不要求“范围锁”,因此可能会发生“幻影读” 。【重点】
4. 可串行化(Serializable)
最高的隔离级别。基于锁机制并发控制的DBMS上,同样会对选定对象上的读锁 和 写锁直到事务结束后才能释放。在select的查询中使用一个“where”子句来描述一个范围时应该获得一个“范围锁”。这种机制可避免 “幻影读” 现象。
了解:三种读现象(Read phenomena)
SQL 92标准描述了三种不同的一个事务读取另外一个事务可能修改的数据的“读现象”。
以下数据表user为例,模拟两个事务之间交替执行sql
id | name | age |
---|---|---|
1 | 张三 | 20 |
2 | 李四 | 25 |
● 脏读
一个事务读取到另外一个事务还未提交的数据,简称为脏读。(此处不做过多演示,自行查阅)
● 不可重复读
在一次事务中,当一行数据查询两遍得到不同的结果表示发生了不可重复读。
执行顺序 |
事务A | 事务B |
① |
begin; |
|
② |
select * from user where id =1; (查询的结果 age = 20) |
|
③ |
begin; |
|
④ |
update user set age=21 where id = 1; ( 修改age为21) |
|
⑤ |
commit ; |
|
⑥ |
select * from user where id =1; (结果age = 21,同一个事务中两次查询结果不一致) |
➳ 解析:在基于锁的并发控制中 “不可重复读” 现象,发生在当执行 select 操作时未获的读锁(隔离级别:读未提交),或者 select 操作执行完后马上释放了读锁(隔离级别:读已提交)
● 幻读
在一个事务中,在不同的时间执行相同的查询语句返回的结果集不同,则称为幻读(phantom)。
注:两次相同的查询,返回的行数不同即为「幻读」,而不是相同的行中某个字段的变化。
执行顺序 |
事务A | 事务B |
① |
begin; |
|
② |
select * from user where age between 20 and 30; (查询年龄在20-30岁之间的记录,结果集2条) |
|
③ |
begin; |
|
④ |
insert into user(id,age) values(3,27); ( 插入一条age为27岁的记录) |
|
⑤ |
commit ; |
|
⑥ |
select * from user where age between 20 and 30; (结果集有3条) |
➳ 解析:“幻影读”是不可重复读的一种特殊场景,当事务A 执行2次 select ... where 查询一定范围内的数据中间,事务B在表中插入了一行新数据,这条新数据正好满足事务1的 “where”子句。
注:这种正常的 “幻影读” 场景,由于MVCC版本快照的存在,因此在RR级别下是不存在的。
▎幻读:在可重复读级别下的 “特殊场景”
RR级别下,保证了当前事务不会读取到其他事务已提交的 update 操作。但同时,也会导致当前事务无法感知到来自其他事务中的 insert 或 delete 操作。
☛ 例如下图:实验A
✦ 流程解析:开启2个事务
- 在事务A中进行查询操作,此时user表没有数据。 step1
- 在事务B中插入id=1数据,并提交事务。step2
- 然后事务A尝试插入同样id=1的记录,发现报主键冲突错误。step3
- 事务A再次查询,发现和step1的结果一致 (RR下的 MVCC机制),彷佛出现了“幻觉”。 step4
A:“见鬼!表里不是没有记录吗??” ,由于RR下的 MVCC机制,因此A无论读取多少次,都查不到 id=1的记录,但它的确无法插入,这条通过读取而认定id=1不存在的记录。
注:A读取的数据状态并不能支持他的下一步的业务,见鬼了一样。
所以:MySQL的 InnoDB引擎在RR级别下到底能否解决幻读?
也可以说能够解决 “幻读”,但可能存在幻写读......
如果面试时遇到这个问题, 可能需要详细给他扯一扯. 需要讲清楚 MySQL InnoDB RR 隔离级别 的快照,快照读 & 当前读
- 在只读时是可以避免幻读的
- 在读写时可能会因为update操作使得不可见的行变得可见, 从而出现幻影行!
☛ 例如下图:实验B
1. demo表原数据如下。注:表中不存在id=2的记录,接下来模拟事务插入数据展示幻读效果。
2. 开启事务,执行顺序依次按照序号执行
时间顺序 |
事务A | 事务B |
① |
begin; (开始事务) |
|
② |
select * from demo where age between 16 and 21; (第一次查询:age为16-21之间的记录) |
|
③ |
begin; (开始事务) |
|
④ |
insert into demo(id, age, d) values (2,17,0); (插入一条age=17的记录,满足事务A条件) |
|
⑤ |
commit ; (提交事务) |
|
⑥ |
update demo set age=18 where id=2; (修改age=17的记录,在②的查询中是不存在的) |
|
⑦ |
select * from demo where age between 16 and 21; (第二次查询:age为16-21岁之间的记录) |
|
⑧ |
commit ; (提交事务) |
✦ 解析:
由于使用一致性非锁定读时是不加锁的,即②,虽然RR级别能使用Next-Key lock, 但在这里也是没有开启的,这就允许事务B进行④插入操作了。【快照读不加锁】
另外事务A执行⑥ update操作时,update 属于当前读(即锁定读),因此不受read-view限制,它会去竞争要修改的数据行的锁。【快照读变更为当前读】
最终会对 trx_id 处于read-view中的数据行(快照读不可见) 进行了修改,id=2的数据行的trx_id 被修改为当前事务A的trx_id,最后select时,就变得可见了 【trx_id 发生修改】
如果前后两次select 都不加锁,基于MySQL的read-view机制,能够保证前后读的数据一致,但如果两次select之间存在update,由于当前读不受read-view限制,最终可能会影响trx_id的修改,从而产生幻影读。但这种是否应该算作幻读呢?
RR级别下InnoDB解决常规幻读的原理
注:MVCC 和 Next-key Locks,能够解决在可重复读的事务隔离级别下出现的幻读
- 快照读:不加锁,通过mvcc来避免幻读。
- 当前读:加锁读,通过next-key来避免幻读。对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁(间隙锁),新的满足查询条件的记录不能够插入 。不存在幻读现象。
➳ 解析:加锁读例如select .. for update / select .. lock in share mode 显式加读锁/写锁;对于insert/update/delete 语句, 它们只有当前读, 且会自动对相应的行加写锁。
▎通俗理解
- 对于快照读来说:你随便读我不管你,反正你读的是历史数据,绝对不会出现幻读。
- 对于当前读来说:需要使用 Next-Key Lock,以实现对写数据进行阻止,防止出现幻读。
扩展:MVCC只会在这两种事务级别工作:
- 读已提交 Read Committed (每次select会生成新的快照)
- 可重复读 Repeatable Read (后续的select都会参照第一次select生成的快照)
因为 读未提交 总是读取最新的数据,不符合当前事务版本的数据行,而 可串行化 则会对所有的行加锁,这两种都不需要MVCC。
▎总结
最后重温一下MySQL官方对幻读(phantom)的定义:“ 同一个事务中,在不同的时间执行查询返回的结果集不同,则称为幻读。”
综上所述,在 实验A、实验B 中我们认为的 “幻读” ,对MySQL来说,并非 “幻读”,而是快照读。
根据官方文档的说法,在RR事务隔离级别:当前读的场景下,在搜索和扫描索引的时候使用next-key locks 可以避免幻读。而快照读则通过mvcc版本控制避免幻读。
面试官:MySql在Repeatable Read下面是否会有幻读出现?相关推荐
- 可重复读(Repeatable read)能防住幻读吗?
文章目录 可重复读(Repeatable read)能防住幻读吗? 事务隔离级别 事务的并发问题 概念 幻读和不可重复读的区别 乐观锁与悲观锁 悲观锁 乐观锁 数据版本 MVCC 当前读 Next-K ...
- Mysql学习(六)-- innodb如何避免幻读及MVCC和间隙锁详解
1. 问题:间隙锁导致死锁 最近由于想让代码快一点把一段代码逻辑从:查询->存在即删除->插入:改成了:根据条件删除->插入. 后来查看数据发现很多数据都不见了,不知道出现了什么bu ...
- mysql不可重复读是锁的表吗,Mysql事务,并发问题,锁机制-- 幻读、不可重复读(转)...
. 例如: 张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5000,汇入100,并提交数据库,工资变为5100, 随后 事务A发生异常,回滚了,恢复张三的工资为5000,这样就导致 ...
- MySQL可重复读隔离级别能解决幻读吗?
事务及事务隔离级别 innodb存储引擎支持事务,myisam不支持事务 事务内的操作要么全部成功,要么全部失败,中途有失败则回滚 事务的ACID:原子性,一致性,隔离性,持久性 事务隔离级别需要解决 ...
- mysql幻读和不可重复读的区别_面试官:MySQL的可重复读级别能解决幻读吗
Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...
- 不可重复读和幻读的区别_面试官:MySQL的可重复读级别能解决幻读吗
Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...
- 面试官:你说熟悉MySQL,那来谈谈InnoDB怎么解决幻读的?
1. 结论 首先说结论,在RR的隔离级别下,Innodb使用MVCC和next-key locks解决幻读,MVCC解决的是普通读(快照读)的幻读,next-key locks解决的是当前读情况下的幻 ...
- MySQL事务(脏读、不可重复读、幻读)
1. 什么是事务? 是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作:这些操作作为一个整体一起向系统提交,要么都执行.要么都不执行:事务是一组不可再分割的操作集合(工作逻辑单元): ...
- MySQL 事务默认隔离级别?能否解决幻读?
事务隔离级别 MySQL 中事务隔离级别有 read uncommited.read commited.repeatable read.serializable 四种,其中默认为 repeatable ...
最新文章
- Java exception handling best practices--转载
- Java功底之static、final、this、super
- c语言哪个方法称为程序大门,学会这8个经典小程序,就相当于跨入了C语言大门...
- Vue项目开发过程中解决跨域问题(vue.config.js结合axios)
- SharePoint 2013 Nintex Workflow 工作流帮助(九)
- Oracle dbms_random随机函数包
- 【英语学习】【Daily English】U02 Daily Routine L02 I go to the gym every other day
- vue 3.2 的 script setup 语法
- 腾讯云linux读取windows数据盘,腾讯云服务器Centos挂载数据盘的方法
- python共享单车数据分析_共享单车数据可视化分析(Python/Seaborn)
- 组合数怎么用计算机算方差,投资组合的方差公式是什么?怎么算的
- HTML5入门 之下拉菜单
- 手把带你学会红外避障循迹模块
- 不是所有的大作业都叫微信抢票大作业
- 幸存与否 ——泰坦尼克号沉船事件数据分析*
- 拼多多校招----大整数相乘(python)
- 《c++ Primer Plus 第6版》读书笔记(4)
- 上海财经应用统计考python_2020上财应用统计432考研高分经验贴
- 关于logarithmicDepthBuffer属性
- 遗留系统的技术栈迁移
热门文章
- bom csv java_JAVA导出CSV乱码问题
- c++顺序栈基本操作实现
- oracle revoke 列_Oracle Grant 与 Revoke的用法
- 伪随机序列调相位C语言,伪随机序列的研究与仿真.doc
- 软件测试人员常用的sql语句(一)
- 网站建设之优质软文“赢”销不可或缺
- 【FPGA】MicroBlaze小试01-串口输出Hello World(demo,熟悉开发流程)
- 【数论】求素数的三种方法
- 牛客错题、好题研究整理
- CSS+DIV进行的页面布局