如何验证 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题及其原因

  • 验证的流程
  • 自助验证
  • 为什么 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题

  很多人都知道,MySQL 的 InnoDB 在事务隔离级别 REPEATABLE READ 下解决了不可重复读的问题,但是依然有幻影行问题。不过很多人都不知道这是为什么,也有很多错误的解释与验证。

  下面开始验证。首先要区分两个概念,正在观察的事务、其它事务。正在观察的事务指的是用于界定事务是否发生幻影行的事务,正在观察的事务只存在一个。其它事务是会对正在观察的事务的操作进行干扰的事务,其它事务可不唯一。

验证的流程

验证的算法如下:

  1. 在 MySQL 创建任意一个数据库、表,将引擎设为 InnoDB。然后在表中初始化任意的数据。

  2. 在不同的客户端下分别开启对同一个 MySQL 数据库的连接。不妨将名字设为客户端 A,客户端 B。其中,客户端 A 是进行正在观察的事务的客户端,客户端 B 是进行其它事务的客户端。

  3. 在客户端 A、B 中设置会话范围的可重复读(REPEATABLE READ)事务隔离级别。

  4. 分别在客户端 A,客户端 B 中开始事务。不妨将名字分别设为事务 a,事务 b。

  5. 分别在客户端 A,客户端 B 查询全表数据。此时,它们的查询结果应该是一样的。

  6. 在事务 b 中插入一个新的数据行,但不提交。

  7. 在事务 a 中查询全表数据,此时的查询结果应该没有变化,因为这是不会发生脏读的特性。

  8. 在事务 b 中提交事务,事务 b 结束。

  9. 在事务 a 中查询全表数据,此时的查询结果应该仍然没有变化,因为这是可重复读的特性。

  10. 在事务 a 中更新那个在事务 b 被插入的数据行。虽然这个数据行没有在前面事务 a 的查询中出现,但此时在事务 a 中却显示受到影响的行数为 1,这说明更新操作成功。

  11. 在事务 a 中查询全表数据,此时会发现在事务 b 中被插入的那个行。这说明出现了幻影行。因为事务 a 并没有插入任何数据,它只是更新了一个在它眼里本来就不会存在的数据。如果没有出现幻影行,那么事务 a 中更新数据的时候,受到影响的行数应该是 0。

  12. 至此,验证结束。


【验证的误区】

以下情况下,不能算是验证了幻影行。

  • 在客户端 A 中,事务 a 查询数据后,提交了本事务(事务 a 结束),然后又开始查询,并发现了数据的变化。

  • 在客户端 A 中,没有显式地开始事务,然后发现了两次查询结果之间的差异。

  • 在事务 a 中插入数据之后的查询中发现了刚刚由事务 a 插入的数据。


自助验证

为了便于读者自行快速验证,这里给出了示例 MySQL 代码,仅供参考。

# 建表
CREATE TABLE test(id INT,username VARCHAR(20)
)ENGINE=InnoDB;# 初始化表中数据
INSERT INTO test VALUES(1,'a'), (2,'b'),(3,'c'),(4,'d');# 设置会话范围的可重复读事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;# 设置全局范围的可重复读事务隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;# 查看事务隔离级别
select @@transaction_isolation;# 开始事务
START TRANSACTION;# 查找全表数据
SELECT * FROM test;# 更新表中数据
UPDATE test SET username='fff' WHERE id=5;# 提交
COMMIT;# 回滚
ROLLBACK;

为什么 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题

  前面已经验证了 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题,现在来谈谈这种情况为什么会发生。

  可重复读是 InnoDB 通过 MVCC(多版本并发控制,Multi-Version Concurrency Control)机制来实现的。InnoDB 会为每个数据行记录行的创建时间、过期时间。以及每次查询的行的版本号、查询所在事务的版本号。这样一来,只要本事务没有变更数据,那么连续同条件的查询结果应该是一样的。

  但是,这种机制只适用于查询,更新数据不会从中获益。更新数据时,就算是更新前面查询中不存在的数据,这种更新也不会引发异常,甚至更新成功了,这就会导致 InnoDB 对行的版本进行更新。由于这个更新是在本事务中进行的,因此在更新之后的下一次查询中将会出现这些数据,也就是幻影行。

如何验证 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题及其原因相关推荐

  1. mysql事务的重复性读_Mysql下InnoDB的可重复读级别的事务测试

    Mysql下InnoDB的可重复读的事务测试 ### 背景: * mysql版本:Server version: 5.1.71 * 操作系统:CentOS 6.5 X64 * 事务隔离级别:不可重复读 ...

  2. innoDB可重复读级别是否可以隔离幻行读

    import java.io.*; import java.sql.*; import java.util.Properties;/**** 验证innoDB可重复读级别是否可以隔离幻行读*** 查看 ...

  3. mysql中mvcc解决不可重复读

    最近在了解了mysql中事务的隔离级别,记录一下 事务的隔离级别: 隔离级别 脏读 不可重复读 幻读 读未提交 read-uncommitted 是 是 是 读已提交 read-committed 否 ...

  4. MySQL 幻读和不可重复读的区别

    背景 最近在学习 MySQL 的事务,幻读和不可重复读很容易搞混.故做此记录总结.先给出两者的定义. 不可重复读 如果一个事务修改了另一个未提交事务读取的数据,就意味着发生了不可重复读现象. r1[x ...

  5. 关于数据库隔离级别为RR(可重复读)下是否解决幻读问题

    一.数据库隔离级别 隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读 READ UNCOMMITTED 是 是 是 否 READ COMMITTED 否 是 是 否 REPEATABLE R ...

  6. mysql幻读和不可重复读的区别_面试官:MySQL的可重复读级别能解决幻读吗

    Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...

  7. 简单聊聊mysql的脏读、不可重复读、幻读

    最近,在一次 mysql 死锁的生产事故中,我发现,关于 mysql 的锁.事务等等,我所知道的东西太碎了,所以,我试着用几个例子将它们串起来.具体做法就是通过不断地问问题.回答问题,再加上" ...

  8. mysql 幻读和不可重复读_幻读和不可重复读的区别

    MySQl MySql默认的隔离级别为Repeatable Read,因此只会出现幻读的情况. 幻读 事务在插入已经检查过不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测获取到的数据如同鬼影一 ...

  9. MySQL事务(脏读、不可重复读、幻读)

    1. 什么是事务? 是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作:这些操作作为一个整体一起向系统提交,要么都执行.要么都不执行:事务是一组不可再分割的操作集合(工作逻辑单元): ...

最新文章

  1. springMVC 拦截器
  2. 近期活动盘点:2019第六届世界互联网大会、智慧城市的人本尺度城市形态讲座、高管AI大数据能力研修班、英伟达初创企业展示开启报名...
  3. c#_HashSet
  4. 1分钟10万字大法:量子波动速读、蒙眼翻书穿针,这是席卷15省的最新智商税...
  5. Go语言 defer
  6. 美国计算机专业 学校推荐信,美国大学计算机专业推荐信范文
  7. 前端面试常见HTML问题(一)
  8. VMware虚拟机不能上网的解决方法
  9. python函数里面,一个*是可变参数的元祖,两个*是可变参数的字典
  10. 移动端,fixed bottom问题
  11. 高效程序员应该养成的七个习惯
  12. 信息采集-火车采集器
  13. 【多题合集】【loliの模拟赛】排列组合大套餐
  14. 在使用springMVC时,页面报的404异常
  15. ADSL拨号网络环境下实时视频广播的完美实现
  16. iphone 控制 android手机,Apple iPhone使用Teamviewer远程控制Android手机以实现各种操作,例如远程计时....
  17. 计算机视觉论文-2021-06-01
  18. 视频解析工具youtube-dl
  19. 数字信号处理——时域采样和频域采样(matlab)
  20. 光伏窗性能研究(3)——单层光伏窗节能性能研究

热门文章

  1. JSP学习总结:2006
  2. Python爬虫人工智能大数据全栈视频史上最全合辑教程分享!
  3. Linux getcwd()的实现【转】
  4. python2.7安装setuptools-36.6.0报ascii' codec can't decode byte 0xce in position 7问题
  5. 《区块链开发指南》一一第1章 区块链基础
  6. php设计模式的六大原则(二):开闭原则
  7. ActionScript接收socket服务器发送来的数据
  8. php session/完整判断是否https/对象与数组互转/文件下载
  9. jQuery Mobile页面返回无需重新get
  10. c#在WinForm中重写ProgressBar控件(带%的显示)