RR有幻读问题吗?MVCC能否解决幻读?

算法映星使
• 阅读 414

幻读是 MySQL 中一个非常普遍,且面试中经常被问到的问题,如果你还搞不懂什么是幻读?什么是 MVCC?以及 MySQL 中的锁?那么请好好收藏和阅读本篇文章,因为它非常重要。

RR 隔离级别

在 MySQL 中,RR 代表 Repeatable Read(可重复读),是数据库事务隔离级别中的一种,它的特性是保证同一个事务中,多次读取同一条记录时,读取到的数据都是一致的。它也是 MySQL 默认的事务隔离级别。

隔离级别是数据库管理系统为了处理并发访问时,控制事务之间相互影响的程度而定义的一组规则。

MVCC

MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种并发控制机制,用于在数据库系统中处理并发读写操作时保持数据的一致性和隔离性(主要是用来解决幻读问题的)。MVCC 通过在每个数据行上保存多个版本的数据来实现并发读取和写入的一致性。

MVCC 的核心思想是将每个事务的读操作与写操作解耦,通过保存数据的历史版本来实现并发控制。每个事务在开始时会创建一个读视图(Read View),用于确定在事务开始时可见的数据版本。读视图包含一个事务开始时的系统版本号,用于与数据行的版本号进行比较,以确定数据行是否对事务可见。

在 MVCC 中,当一个事务执行写操作时,会生成一个新的数据版本,并将旧版本的数据保存在回滚日志(Undo Log)中。这样,其他事务在读取数据时仍然可以访问到旧版本的数据,从而避免了幻读问题。

MVCC 工作流程如下:

  1. 读操作:当一个事务执行 SELECT 语句时,会根据读视图的系统版本号和数据行的版本号进行比较,只读取在事务开始之前已经提交的数据行。这样,即使其他事务正在并发地插入或删除数据,事务仍然可以读取到一致的数据。
  2. 写操作:当一个事务执行 INSERT、UPDATE 或 DELETE 语句时,会生成新的数据版本,并将旧版本的数据保存在回滚日志中。这样,其他事务在读取数据时仍然可以访问到旧版本的数据,从而避免了幻读问题。

MVCC 机制在数据库系统中广泛应用,特别是在支持事务的存储引擎中,如 MySQL 的 InnoDB 引擎。它通过解耦读操作和写操作,提供了高并发性能和数据一致性,使得多个事务可以同时读取和修改数据库,而不会相互干扰。

RR + MVCC 有幻读问题吗?

在 MySQL 中,即使是RR 隔离级别(可重复读),虽然它通过 MVCC 消除了绝大部分幻读问题,但依旧存在部分幻读问题,所以 RR 隔离级别存在幻读问题,而 MVCC 也没有彻底解决幻读问题。

幻读问题演示

在 RR 隔离级别中存在两种读操作:

  1. 快照读:数据库中一种读取数据的方式,它基于事务开始时的一个一致性快照来读取数据。快照读可以提供事务开始时的数据视图,即使在事务执行期间其他事务对数据进行了修改,也不会影响快照读取到的数据。简单理解,快照读就是事务开启时创建一个缓存,之后的查询都会从这个缓存中获取数据。
  2. 当前读:数据库中一种读取数据的方式,它读取最新提交的数据,而不是基于事务开始时的一致性快照。

所以,在 RR 隔离级别中 MVCC 通过快照读的方式解决了大部分幻读问题,但如果 RR 隔离级别存在当前读(使用 select ... for update 实现),那么此时也会发生幻读问题,比如以下执行过程:
RR有幻读问题吗?MVCC能否解决幻读?

如何彻底解决幻读?

想要彻底解决幻读问题,有两个方案:

  1. 使用串行化(Serializable)隔离级别:官方推荐方案,但这种解决方案,并发性能比较低。
  2. RR + 锁:使用 RR 隔离级别,但在事务开启之后立即加锁,如下图所示:RR有幻读问题吗?MVCC能否解决幻读?事务一开启之后就加锁,之后其他事务在操作此表的相关数据时,就只能等待锁释放(事务一提交或回滚锁自动释放)。

    小结

    在可重复读级别中,MySQL 虽然使用 MVCC 解决了大部分幻读问题,但在当前读的操作中依然有幻读问题,此时可以通过加锁,或升级隔离级别为串行化来解决幻读问题。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。
点赞
收藏
评论区
推荐文章
Peter20 Peter20
4年前
【MySQL笔记】正确的理解MySQL的MVCC及实现原理
MVCC多版本并发控制如果觉得对你有帮助,能否点个赞或关个注,以示鼓励笔者呢?!!首先声明,MySQL的测试环境是5.7前提概要什么是MVCC什么是当前读和快照读?当前读,快照读和MVCC的关系MVCC实现原理隐式字段undo日志ReadView(读视图)
OMG!Java高级开发岗必问知识点
目录1.Mysql2.CHAR与VARCHAR的区别?3.能说下myisam和innodb的区别吗?4.你能说下事务的基本特性和隔离级别吗?5.并发问题脏读、不可重复读、幻读?6.事务的隔离级别?7.说说自增主键、UUID?8.mysql的约束分类?9.drop、delete与tru
Peter20 Peter20
4年前
Mysql中MVCC的使用及原理详解
数据库默认隔离级别:RR(RepeatableRead,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别创建一张存储引擎为testmvcc的表,sql为:CREATETABLEtestmvcc(idint(11)DEFAULTNULL,namevarchar(11)DEFAULTNULL)ENGINE\InnoDB
Wesley13 Wesley13
3年前
mysql 事务隔离级别
1. MySQL事务隔离级别,默认是可重复读(repeatableread)事务隔离级别脏读不可重复读幻读读未提交(readuncommitted)是是是不可重复读(readcommitted)否是是可重复读(repeatableread)否否是串行化(serializable)
Wesley13 Wesley13
3年前
Mysql RR下的幻读问题
网络上大部分的文章都是这么说的:RR下面是不会发生的。经过一番查证,我想说这个结果是错误的。下面我来举证说明:autogenerateddefinitioncreatetabletest(c1intauto_incrementprimarykey,c2
Stella981 Stella981
3年前
SSM框架(3):配置Spring的事务管理器,实现事务控制
 一、相关概念1、不可重复读和幻读的区别  很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。  如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但
Wesley13 Wesley13
3年前
MySQL的可重复读级别能解决幻读吗
引言之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题。为了更好的理解所以在MySQL数据库中测试复现这些问题。关于脏读和不可重复读在相应的隔离级别下都很容易的复现了。但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理?测试:创建一张测试用的表dept:CREAT
Easter79 Easter79
3年前
SSM框架(3):配置Spring的事务管理器,实现事务控制
 一、相关概念1、不可重复读和幻读的区别  很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。  如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但
Wesley13 Wesley13
3年前
Mysql事务隔离实现机制
今天我们来看看事务隔离的实现原理事务隔离隔离性与隔离级别当数据库上有多个事务同时执行的时候,就可能出现脏读(dirtyread)、不可重复读(nonrepeatableread)、幻读(phantomread)的问题,为了解决这些问题,就有了“隔离级别”的概念在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会
Wesley13 Wesley13
3年前
MySQL 到底是怎么解决幻读的?
!(https://oscimg.oschina.net/oscnet/499dba19ff154743936c6a6b53f27ea9.jpg)作者:LastSunhttps://www.cnblogs.com/wdy1184/p/10655180.html一、什么是幻读在一次
事务的ACID,隔离级别,脏读,幻读和不可重复读
事务的ACID原子性(atomicity)一个事务中执行的sql语句,要么全部成功,要么全部失败,不可能一部分成功。一致性(consistency)事务执行前和执行后数据一致,也就是说事务中的sql语句不能只执行一部分。这种请款一般发生在事务异常中断,服