MySQL InnoDB引擎在Repeatable Read(可重复读)隔离级别下,到底有没有解决幻读的问题?

网上众说纷纭,有的说解决了,有的说没解决,甚至有些大v的意见都无法达成统一。

今天就深入剖析一下,彻底解决这个幻读的问题。

解决幻读问题之前,先普及几个知识点。

1. 并发事务产生的问题

先创建一张用户表,用作数据验证:

CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';

并发事务会产生下面三个问题:

脏读

定义: 一个事务读到其他事务未提交的数据。

从上面的示例图中,可以看出,在事务2修改完数据,没有提交的情况。事务1已经读到事务2最新修改的数据,这种情况就属于脏读。

不可重复读

定义: 一个事务读取到其他事务修改过的数据。

从上面的示例图中,可以看出,在事务2修改完数据,并提交事务后。事务1第二次查询已经读到事务2最新修改的数据,这种情况就属于不可重复读。

幻读

定义: 一个事务读取到其他事务最新插入的数据。

从上面的示例图中,可以看出,在事务2插入完数据,并提交事务后。事务1第二次查询已经读到事务2最新插入的数据,这种情况就属于幻读。

2. 快照读和当前读

再普及一下快照读和当前读。

快照读: 读取数据的历史版本,不对数据加锁。

例如:select

当前读: 读取数据的最新版本,并对数据进行加锁。

例如:insert、update、delete、select for update、select lock in share mode。

3. 再谈幻读问题

MySQL在Repeatable Read(可重复读)隔离级别下,到底有没有解决幻读的问题?

只能说是部分解决了幻读问题。

首先,在快照读的情况下,是通过MVCC(复用读视图)解决了幻读问题。

想详细了解MVCC和读视图,可以翻一下上篇文章。

先手动设置一下MySQL的隔离级别为可重复读:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

执行测试用例,验证一下:

从上面的示例图中,可以看出,事务1的两次查询,得到的结果一致,并没有查到事务2最新插入的数据。

原因是,在可重复读隔离级别下,第一次快照读的时候,生成了一个读视图。第二次快照读的时候,复用了第一次生成的读视图,所以两次查询得到的结果一致。

所以,在快照读的情况下,可重复读隔离级别是解决了幻读的问题。

再测试一下,在当前读的情况下,可重复读隔离级别是否解决幻读问题:

从上面的示例图中,可以看出,事务1的两次查询,得到的结果不一致。在事务2插入数据,并提交事务后。事务1的第二次执行当前读(加了for update)的时候,读到了事务2最新插入的数据。

原因是,在可重复读隔离级别下,每次执行当前读会生成一个新的读视图,所以能读到其他事务最新插入的数据。

所以,在当前读的情况下,可重复读隔离级别是没有解决了幻读的问题。

在执行上面的测试用例的时候,我忽然想到一个问题,既然select for update的当前读,出现了幻读问题,是不是其他的当前读也会复现幻读问题,比如insert。

再执行测试用例,验证一下:

跟预想的一样,在insert当前读的情况下,也出现了幻读的问题(主键冲突)。

那有没有什么办法?在可重复读隔离级别下,执行当前读的时候,也能解决幻读的问题?

当然有的,唯一的办法就是加锁。

事务1在执行第一次查询的时候,就对数据进行加锁(使用for update),防止其他事务修改数据,这样也就彻底解决了幻读问题。

你觉得有什么好办法吗?

MySQL到底有没有解决幻读问题?这篇文章彻底给你解答的更多相关文章

  1. MySQL 到底是怎么解决幻读的?

    ; 原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的. 2. next-key 锁 (当前读) next-key 锁包含两部分: 记录锁(行锁) 间隙锁 记录锁是加在 ...

  2. MySQL到底能否解决幻读问题

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

  3. MySQL 是如何解决幻读的

    MySQL 是如何解决幻读的 一.什么是幻读 在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读. 而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证 ...

  4. MySQL的可重复读级别能解决幻读吗

    引言 之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了.但是对于幻 ...

  5. MYSQL如何解决幻读

    第一部分 首先要了解下mysql数据库的事务特征之一隔离级别: READ UNCOMMITTED(未提交读): 在READUNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的 ...

  6. 何为幻读?MySQL又是如何解决幻读的?

    一.什么是幻读 在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读.而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证事务与事务之间的隔离性,还 ...

  7. 【大厂面试03期】MySQL是怎么解决幻读问题的?

    问题分析 首先幻读是什么? 根据MySQL文档上面的定义 The so-called phantom problem occurs within a transaction when the same ...

  8. MySQL锁(三)行锁:幻读是什么?如何解决幻读?

    概述 前面两篇文章介绍了MySQL的全局锁和表级锁,今天就介绍一下MySQL的行锁. MySQL的行锁是各个引擎内部实现的,不是所有的引擎支持行锁,例如MyISAM就不支持行锁. 不支持行锁就意味着在 ...

  9. MySQL的可重复读级别能解决幻读问题吗?

    之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于幻读, ...

随机推荐

  1. 程序分析与优化 - 9 附录 XLA的缓冲区指派

    本章是系列文章的案例学习,不属于正篇,主要介绍了TensorFlow引入的XLA的优化算法.XLA也有很多局限性,XLA更多的是进行合并,但有时候如果参数特别多的场景下,也需要进行分割.XLA没有数据 ...

  2. Linux系列之查找命令

    前言 Linux 有四个常用的查找命令:locate.whereis.which 和 find.本文介绍它们的区别和简单用法. locate命令 这个命令将检查你的整个文件系统,并找到该关键词的每一次 ...

  3. ReentrantLock 公平锁源码 第1篇

    ReentrantLock 1 这篇还是接着ReentrantLock的公平锁,没看过第0篇的可以先去看上一篇https://www.cnblogs.com/sunankang/p/16456342. ...

  4. Jetty 源码解析 - 流程

    前言 公司实习分配给的任务是精简和优化 Jetty 框架,这里做简单的思路记录(比较乱),源码是 Jetty 7.x.x . 大体流程 Connector 接口的实现类 SelectChannelCo ...

  5. JsonPath:针对json的强大的规则解析与参数查找工具

    项目特点 GitHub项目地址:https://github.com/json-path/JsonPath 主要功能: 将Json字符串转为Java Map对象(这个不算什么,FastJson之类的工 ...

  6. Webpack干货系列 | 在 Webpack 5 集成 ESLint 的方法

    程序员优雅哥(youyacoder)简介:十年程序员,呆过央企外企私企,做过前端后端架构.分享vue.Java等前后端技术和架构. 本文摘要:主要讲解运用Webpack 5 中集成 ESLint 的方 ...

  7. C#/VB.NET: 将Word或Excel文档转化为Text

    Text文件只由纯文本内容组成,且没有格式,所以其大小比Word或Excel文件更小.除此之外,Text文件还具有跨平台性,几乎与所有应用程序都兼容.因此,在某些时候,我们可能需要将Word或Exce ...

  8. K阶斐波那契数列--------西工大NOJ习题.10

    K阶斐波那契数列--------西工大NOJ习题.10 原创不易,转载请说明出处!!! 科普:k阶斐波那契数列的0到n-1项需要有初始值. 其中,0到n-2项初始化为0,第n-1项初始化为1. 在这道 ...

  9. cad工具快速选择特性里面是空的解决方法

    工具-选项-文件中,支持文件搜索路径中 添加,再浏览,找到"C:\Program Files\Common Files\Autodesk Shared"确定就OK了.

  10. 封装Fraction-分数类(C++)

    Fraction 分数类 默认假分数,可自行修改 由于concept的原因 template <typename T> concept is_float_v = std::is_float ...