我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MySQL(九):MVCC能否解决幻读问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MySQL(九):MVCC能否解决幻读问题

尺有所短,寸有所长;不忘初心,方得始终

请关注公众号:星河之码

幻读【前后多次读取,数据总量不一致】

同一个事务里面连续执行两次同样的sql语句,可能导致不同结果的问题,第二次sql语句可能会返回之前不存在的行。

事务A执行多次读取操作过程中,由于在事务提交之前,事务B(insert/delete/update)写入了一些符合事务A的查询条件的记录,导致事务A在之后的查询结果与之前的结果不一致,这种情况称之为幻读

  • MVCC能否解决幻读问题

    首先可以明确的是,MVCC在快照读的情况下可以解决幻读问题,但是在当前读的情况下是不能解决幻读的

一、快照读和当前读

mysql里面实际上有两种读取的方式:快照读和当前读,在之前的文章中《MySQL(八):MVCC多版本并发控制》也有介绍,这里重新简单回顾一下。

  • 快照读【Consistent Read】

    也叫普通读,读取的是记录数据的可见版本,不加锁,不加锁的普通select语句都是快照读,即不加锁的非阻塞读

    快照读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁

    如下语句:

    select * from table;
  • 当前读

    也称锁定读【Locking Read】,读取的是记录数据的最新版本,并且需要先获取对应记录的锁。如下语句:

    SELECT * FROM student LOCK IN SHARE MODE;  # 共享锁SELECT * FROM student FOR UPDATE; # 排他锁INSERT INTO student values ...  # 排他锁DELETE FROM student WHERE ...  # 排他锁UPDATE student SET ...  # 排他锁

二、MVCC能解决幻读问题的场景

当我们在读取数据的时候是【快照读】的情况下是可以解决【幻读】的问题,其原理就是MVCC

下面使用案例说明:

假设表中有三条数据,以及有两个事物A/B,A读取数据,B插入数据

#事物A:select name from user where id > 3;#事物B:insert into user valus('6','edwin');

执行过程

时间事务A事物C
1开始事务
2第一次查询:select name from user where id > 3;
6开始事务
7执行插入:insert into user valus(‘6’,‘edwin’);
8提交事务
9第二次查询:select name from user where id > 3;
10提交事务

由于采用的是【快照读】的方式,在A事物开启时会产生一个版本快照,产生版本快照如下

然后通过MVCC的【Read View】对版本快照中各个版本链中的数据进行可见性判断,读取相应的数据版本。两次查询结果都是【id=4,5】两条数据。

Read View具体可见性规则判断在之前的文章中《MySQL(八):MVCC多版本并发控制》有详细的图文详解,这里就不再赘述。

因此,即使事务B新插入了数据,由于已经生成了版本快照,也不会影响Read View的可见性规则判读,所以在【快照读】的情况下,使用MVCC不会产生幻读问题。

三、MVCC不能解决幻读问题的场景

3.1、MVCC什么场景下不能解决幻读问题

当我们在读取数据的时候是【当前读】的情况下,无法使用MVCC解决幻读问题

案例说明:还是先准备几条数据,

有两个事物A/B,A先读取数据,在修改数据,最后有读取数据,B插入数据,看看结果会什么

#事物A:select name from user where id > 3;#事物B:insert into user valus('6','edwin');#事物A:update user set name = '彬' where id = 6;

执行过程

时间事务A事物C
1开始事务
2第一次查询:select name from user where id > 3;
6开始事务
7执行插入:insert into user valus (‘6’,‘edwin’);
8提交事务
9第二次查询:select name from user where id > 3;
10修改数据:update user set name = ‘彬’ where id = 6;
11第三次查询:select name from user where id > 3;
12提交事务
  • 在时间点为9的时候

    事务A的【第一次】与【第二次】查询结果与上面的快照读是一样的,基于MVCC两次查询结果都是【id=4,5】两条数据。

  • 在时间点为10的时候

    事务A修改了事务B插入的数据,由于update是当前读,所以此时会读取最新的数据(包括其他已经提交的事务)

  • 在时间点为11的时候

    事务A执行【第三次】查询,是基于当前最新版本查询的,所以会查询到事务B插入的【id=6】的数据,一共会查询到三条数据【id=4,5,6】,与前两次查询结果不同,从而产生了幻读。

3.2、如何解决当前读的幻读问题

在可重复读(RR)的隔离级别下,执行当前读,

案例说明:还是使用上述的数据

  • 事务A,执行当前读,查询id>3的所有记录。
  • 事务B,插入id=5的一条数据。
#事物A:select name from user where id > 3 lock in share mode;#事物B:insert into user valus('6','edwin');

执行过程

时间事务A事物B
1开始事务
2第一次查询:select name from user where id > 3 lock in share mode;
6开始事务
7执行插入时发现,id>3的范围有间隙锁,插入阻塞,处于等待状态
8第二次查询:select name from user where id > 3;
9提交事务
10事物A提交,间隙锁释放,执行插入:insert into user valus (‘6’,‘edwin’);
11提交事务

事务A在执行当前读【select … lock in share mode】的时候,在【id=4,5】的记录上加了共享锁,并且在【id > 6】这个范围上也加了间隙锁,所以上图中的事务B执行插入操作时被阻塞了。所以事务A两次读取的数据是一样的。因此,在这种情况下是不会存在幻读问题。

  • 总结

    RR隔离级别下,当前读执行如下语句时会带上锁之外,还会使用间隙锁+临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录

    SELECT * FROM student LOCK IN SHARE MODE;  # 共享锁SELECT * FROM student FOR UPDATE; # 排他锁INSERT INTO student values ...  # 排他锁DELETE FROM student WHERE ...  # 排他锁UPDATE student SET ...  # 排他锁
  • 注意

    这种方式不能解决3.1中的幻读问题,因为在3.1中事务A执行修改数据,获取锁之前,已经读取到了事务B插入的数据,并且已经记录到Undo日志中

来源地址:https://blog.csdn.net/Edwin_Hu/article/details/124392174

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MySQL(九):MVCC能否解决幻读问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL(九):MVCC能否解决幻读问题

尺有所短,寸有所长;不忘初心,方得始终。 请关注公众号:星河之码 幻读【前后多次读取,数据总量不一致】 同一个事务里面连续执行两次同样的sql语句,可能导致不同结果的问题,第二次sql语句可能会返回之前不存在的行。 事务A执行
2023-08-17

【MySQL】MVCC是如何解决快照读下的幻读问题的

文章目录 LBCC当前读 MVCC隐藏列undo logRead View 总结 我们从上文中了解到InnoDB默认的事务隔离级别是repeatable read(后文中用简称RR),它为了解决该隔离级别下的幻读的并发问
2023-08-17

MySQL如何解决幻读问题

目录前言一、什么是幻读?二、幻读有什么问题?(1)需要单独解决(2)间隙锁引发的并发度三、如何解决幻读?三、总结前言我们知道MySQL在可重复读隔离级别下别的事物提交的内容,是看不到的。而可提交隔离级别下是可以看到别的事务提交的。而如果我们
2022-05-22

mysql怎么解决幻读问题

MySQL可以通过以下几种方式解决幻读问题:1. 事务隔离级别:将事务的隔离级别设置为串行化(SERIALIZABLE)可以解决幻读问题,因为串行化级别保证了并发事务之间的完全隔离。但是,这也会降低并发性能。2. 使用锁机制:通过使用锁机制
2023-08-23

mysql中怎么使用MVCC来解决幻读

在MySQL中,MVCC(Multi-Version Concurrency Control)是通过在内部保留数据的多个版本来实现并发控制的。这样可以确保一个事务在读取数据时不会被其他事务的写操作所干扰,从而解决了幻读问题。要使用MVCC
mysql中怎么使用MVCC来解决幻读
2024-04-24

MySQL中怎么解决幻读问题

本篇文章给大家分享的是有关MySQL中怎么解决幻读问题,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、什么是幻读?  假设我们有表t结构如下,里面的初始数据行为:(0,0,0
2023-06-20

[MySQL] 有没有解决幻读问题

默认隔离级别下 , mysql没有解决幻读问题 , 需要应用代码里加一个锁来解决幻读问题是啥? 默认的隔离级别是可重复读 REPEATABLE-READ   ,  在这个模式下出现幻读的例子一般是这两种情况:事务1和事务2同时 , 事务1读数据 , 事务2插入
[MySQL] 有没有解决幻读问题
2014-06-05

MySQL是怎么解决幻读问题的?

前言  我们知道MySQL在可重复读隔离级别下别的事物提交的内容,是看不到的。而可提交隔离级别下是可以看到别的事务提交的。而如果我们的业务场景是在事物内同样的两个查询我们需要看到的数据都是一致的,不能被别的事物影响,就使用可重复读隔离级别。这种情况下RR级别下
MySQL是怎么解决幻读问题的?
2014-10-24

InnoDB怎么解决幻读问题

这篇“InnoDB怎么解决幻读问题”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“InnoDB怎么解决幻读问题”文章吧。事务隔
2023-07-05

MySQL MVCC 原理分析:如何解决数据并发问题?

MySQL MVCC 原理分析:如何解决数据并发问题?在数据库系统中,数据并发问题是一个非常重要且常见的挑战。在多个用户同时对数据库进行读写操作时,会出现数据不一致、丢失更新等问题。为了解决这些问题,MySQL引入了MVCC(多版本并发控制
2023-10-22

协程能否解决Linux高并发问题

协程是一种轻量级的线程,它可以实现在同一个线程中进行多个任务的切换执行,从而提高程序的并发处理能力。在Linux环境下,协程可以有效地解决高并发问题。通过使用协程,可以避免传统多线程模型中线程切换的开销,从而提高程序的性能和效率。协程可以
协程能否解决Linux高并发问题
2024-08-06

编程热搜

目录