首页 > 其他分享 >RR有幻读问题吗?MVCC能否解决幻读?

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

时间:2023-08-09 17:33:53浏览次数:42  
标签:事务 隔离 RR 幻读 MVCC 数据

幻读是 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 实现),那么此时也会发生幻读问题,比如以下执行过程:
image.png

如何彻底解决幻读?

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

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

小结

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

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

标签:事务,隔离,RR,幻读,MVCC,数据
From: https://www.cnblogs.com/vipstone/p/17617476.html

相关文章

  • MongoDB 位置查询报错 planner returned error: unable to find index for $geoNear q
     执行查询语句,使用 $nearSphere/***1千米=0.6213712英里15千米=9.3205679英里查询通过除以地球的大约赤道半径(3963.2英里)将距离转换为弧度。*①:如果是第一页,查询50公里内的老朋友店铺,*②:查询15公里内所以的置顶服务商家,然后根据分页参数来截取*③:0.0015678......
  • Mirror_World_Address
    NPM_mirror_start:"cmd","/c","npmconfigsetregistryhttps://registry.npmjs.org"NPM_mirror_end;Conda_mirror_start: https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/f......
  • SQL中fetch_array()和fetch_row()的区别
    相同点:两个的作用都是把查询结果的第一行返回到一个数组中。不同点:fetch_row()是通过数字索引取值。$res=mysqli_query($con,$sql);//返回资源$arr=mysqli_fetch_row($res);//查询的第一行结果赋值给$arrprint_r($arr);print_r($arr[0]);fetch_arroc()是通过关键字......
  • golang自定义 os.stderr 数据读取逻辑
    原始需求只是一个很简单的需求,使用golang的exec运行一个命令然后获取实时结果,命令是trivyimage--download-db-only正常的打印应该是2023-08-08T17:06:02.929+0800INFONeedtoupdateDB2023-08-08T17:06:02.929+0800INFODBRepository:ghcr.io/aquas......
  • RuntimeError: DataLoader worker (pid 7978) is killed by signal: Aborted.
    报错信息显示pytorch的DataLoader无法正确加载。造成这个报错的原因不尽相同,但是猜测,大体上都是程序不知为何无法开启新的线程,导致线程被系统终止。当线程数设为0时正常(num_worker=0)对于我来说,发现问题出现在使用vscode调试pytorch训练代码。如果是命令行运行则没问......
  • yum update更新报错 Transaction Check Error 解决方法
    yumupdate更新报错TransactionCheckError解决方法yumupdate引起错误TransactionCheckError的原因很多,要根据错误概要去判断具体原因。错误现象:报错内容:file/usr/share/man/man1/gtk-query-immodules-2.0.1.gzfrominstallofgtk2-2.24.31-1.el7.x86_64conflicts......
  • 软件测试|json.decoder.JSONDecodeError: Expecting ‘,‘错误解决
    在处理JSON数据时,有时可能会遇到"json.decoder.JSONDecodeError:Expecting','"的错误,如下图的情况,本文将介绍这个错误的原因以及一些常见的解决方法。错误原因"json.decoder.JSONDecodeError:Expecting','"错误通常发生在解析JSON数据时,Python解析器期望在JSON对象或数组的元素......
  • TypeError: a bytes-like object is required, not ‘str‘,如何解决?
    在Python编程中,当我们在处理文件或网络传输等场景时,有时可能会遇到以下错误信息:"TypeError:abytes-likeobjectisrequired,not'str'"。这个错误通常表示我们传递了一个字符串对象而不是字节对象,导致了类型不匹配。如下所示,我们对字段进行base64编码时,出现了报错:在本文中,我们......
  • Sqoop 连接mysql 错误 java.lang.NoClassDefFoundError(已解决)
    错误信息Exceptioninthread"main"java.lang.NoClassDefFoundError:org/apache/commons/lang/StringUtilsatorg.apache.sqoop.manager.MySQLManager.initOptionDefaults(MySQLManager.java:73)atorg.apache.sqoop.manager.SqlManager.<init......
  • 遇到的问题--python---IndentationError: unexpected indent
    情况我们在运行python脚本时遇到错误报错IndentationError:unexpectedindent。如下图:原因字母意思就是不希望有缩进,去掉空格和tab。看看我们的代码如下:发现第一行没有顶格写,python对代码的格式要求很严格,python没有分号,用严格的缩进表示上下级从属层级关系,第一行需要顶......