MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别

这篇具有很好参考价值的文章主要介绍了MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 前 言

在正式开始之前,先简单回顾一下并发事务存在的问题以及事务的隔离级别等内容。

1.1 并发事务存在的问题

当两个或者两个以上事务同时开启去处理同一个表的数据时,可能会存在以下的问题:

  • 丢失修改
  • 脏读
  • 不可重复读
  • 幻读

丢失修改

丢失修改是指当两个或多个事务更新同一行记录,产生更新丢失的现象,事务回滚覆盖和事务提交覆盖都会导致这种现象的产生。

脏读

一个事务能读取到另一个事务已经修改但还没有提交的数据。

不可重复读

在一个事务中多次执行同一条查询语句,读取到的数据内容前后不一致。

幻读

在一个事务中多次执行同一条查询语句,读取到的数据记录在数量上前后不一致,可能多了几条记录也可能少了几条记录。

1.2 事务的隔离级别

为了解决并发事务存在的问题,大佬们想到了一个手段,那就是对事务进行隔离,最好是做到各个事务各干各的,互不干涉,但理想很丰满,现实很骨感,哪可能一步到位呢。

为了应对不同的需要,解决不同的问题,于是决定将事务的隔离分成四个级别,分别是:

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化

它们各自能解决的并发事务问题如下表所示:

隔离级别 \ 事务问题 事务回滚覆盖 脏读 不可重复读 事务提交覆盖 幻读
读未提交 能解决 不能解决 不能解决 不能解决 不能解决
读已提交 能解决 能解决 不能解决 不能解决 不能解决
可重复读 能解决 能解决 能解决 能解决 不能完全解决,可能发生
串行化 能解决 能解决 能解决 能解决 能解决

1.3 快照读和当前读

快照读

快照读是基于 MVCC 和 undo log 来实现的,读取数据的历史版本,得到一个 ReadView (事务视图) ,不对数据加锁,适用于简单 select 语句。

这里提一句,所谓 MVCC 并发版本控制,就是靠 ReadView (事务视图) 来实现的,多个 readView 组成 undo log(回滚日志)。

当前读

当前读是基于行锁 + 间隙锁来实现的,读取数据的最新版本,并对数据进行加锁,适用于 insert,update,delete, select ... for update, select ... lock in share mode 语句,以及加锁了的 select 语句

在更新数据时,都是先读后写,而这个读,就是指当前读,意味读取数据时,读到的是该条数据最新生成的 ReadView。

2. 不同事务隔离级别下幻读的区别

在上面的表格中,我们能看到,在读已提交这个隔离级别下,幻读是不能被解决的,也就是说会发生;而在可重复读这个隔离级别下,幻读则是没有完全被解决,只是解决了部分,意味着仍然有可能发生。

那它们分别是怎么产生的?各自又有什么表现?有何区别?下面我们举个例子来探究一下。

假设现在有两个事务,分别是事务 A 和 事务 B ,同时有一张学生表 student(表中只有一条记录,stu_name 为王大) ,我们用这两个事务来操作这张表。

2.1 读已提交下的幻读

在读已提交这种事务隔离级别下,两个事务的操作顺序如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0;
insert into student(stu_name) values(‘李二’);
commit;
开始第二次查询:select * from student where stu_id > 0;
  1. 事务 A 第一次查询,得到的数据记录是 stu_name 为王大这一条
  2. 事务 B 中途往表里插入了一条 stu_name 为李二的记录,并提交自身的事务
  3. 事务 A 用第一次查询的 SQL 语句进行第二次查询时,发现得到的数据记录成了两条,出现幻读

表现

普通的查询语句,能看到明显幻读现象。

原因剖析

事务 A 中用的是普通的 select 语句,因此采用的是快照读,但由于事务隔离级别为读已提交,在读已提交下,每次 select 操作,都会重新获取最新版本的数据,也正是因为这个原因,导致事务 A 中两次查询得到的结果在数量不一致,产生幻读。

解决方式

将事务隔离级别升级为可重复读

2.2 可重复读下的幻读

2.2.1 情况一,无幻读

在可重复读这种事务隔离级别下,两个事务的操作顺序如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0;
insert into student(stu_name) values(‘李二’);
commit;
开始第二次查询:select * from student where stu_id > 0;

像上面这样的事务操作,虽然在读已提交事务隔离级别下会产生幻读,但在可重复读事务隔离级别下,却不会产生幻读。

原因:在可重复读事务隔离级别下,针对普通的 select 语句,采用的是快照读,只会在第一次查询的时候获取一次数据的版本,往后继续做相同的 select 操作,不会重新获取,会延用前面得到的数据版本

细心的你有没有发现,在可重复读事务隔离级别下,对于快照读(普通的 select 操作),这不就是使用 MVCC 解决幻读问题吗?你没看错,是这样的。

2.2.2 情况二,有幻读

在可重复读这种事务隔离级别下,两个事务的操作顺序如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0;
insert into student(stu_name) values(‘李二’);
commit;
开始第二次查询:select * from student where stu_id > 0 for update;

上面的事务操作,和前面不同的地方在于,第二次查询加上了 for update ,也就是采用当前读。

表现

能看到明显的幻读现象

原因剖析

由于事务 A 第二次查询在 SQL 语句末尾加上了 for update ,表示采用当前读的方式,获取数据的最新版本,那么自然而然会把事务 B 中途插入的数据给查出来,从而出现幻读。

解决方式

用 next-key lock 解决,如果是走索引,会锁住索引本身的行锁;如果是范围,就会成为一个行锁+间隙锁,导致范围内的无法插入;如果是无索引的,直接全表加上了间隙锁,无法插入,阻塞。

具体的操作方式如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0 for update;
insert into student(stu_name) values(‘李二’);
commit;
开始第二次查询:select * from student where stu_id > 0 for update;

事务 A 的每次查询都加上 for update,这样就不会出现幻读,原因是事务 B 的 insert 操作会被阻塞,无法将数据插入到表中,从而避免幻读的出现。

2.2.3 情况三,有幻读

在可重复读这种事务隔离级别下,两个事务的操作顺序如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0;
insert into student(stu_name) values(‘李二’);
commit;
update student set stu_class = ‘03’ where stu_id is not null;
开始第二次查询:select * from student where stu_id > 0;

在上面的事务操作下,事务 B 能将数据记录正常插入到表中,而事务 A 做了一次 update 操作,从上面的介绍我们可以知道,update 操作是当前读,会获取到数据的最新版本,自然也能拿到事务 B 的提交记录。

表现

能明显看到幻读现象

原因剖析

事务 A 的 update 操作采用的是当前读,会获取数据的最新版本,将事务 B 提交的结果读取出来,后面事务 A 再做普通的 select 操作,采用快照读,由于延用 update 操作时得到的数据历史版本,因而产生幻读。

解决方式

同 2.2.2 中的解决方式一样,具体操作如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0 for update;
insert into student(stu_name) values(‘李二’);
commit;
update student set stu_class = ‘03’ where stu_id is not null;
开始第二次查询:select * from student where stu_id > 0 for update;

最简单的解决方式,就是再将事务隔离级别升级,改为串行化,毕竟串行化本身就解决所有事务问题,当然,这会牺牲效率。文章来源地址https://www.toymoban.com/news/detail-430943.html

3. 小 结

  1. 并发事务中,对于普通的 select 语句,在读已提交下,能明显看到幻读的现象,而在可重复读下,看不到幻读现象。
  2. 并发事务中,对于事务执行语句里含有当前读的情况,得具体问题具体分析,可能可以看到幻读,也可能由于加了 for update ,看不到幻读。

到了这里,关于MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 生成12位短id,自增且不连续,永不重复,不依赖数据库

    基本思路: 设计模式:单例模式 是否加锁:是 synchronized 获取最后一次生成的时间戳值T0 限定初始时间为2023-08-01 00:00:00,获取当前时间时间戳T1,T1与初始时间的毫秒差值T2,转为16进制,转为字符串为r1,获取该字符串的长度L1 获取L2 (length - L1) ,获取L2位数字的16进制自增数值范围

    2024年02月10日
    浏览(49)
  • java八股文面试[数据库]——可重复读怎么实现的(MVCC)

    可重复读(repeatable read)定义: 一个事务执行过程中看到的数据,总是 跟这个事务 在 启动时 看到的数据是一致的。 MVCC MVCC, 多版本并发控制 , 用于实现 读已提交 和 可重复读 隔离级别。 MVCC的核心就是 Undo log多版本链 + Read view ,“MV”就是通过 Undo log来保存数据的历史版

    2024年02月09日
    浏览(50)
  • 70万无符号无重复网名大全ACCESS\EXCEL数据库

    虽然之前收集过网名数据库,比如:《4万个性网名大全网络名称大全ACCESS数据库》、《8万多个网名大全QQ网名ACCESS数据库》,但是都包含有~!#@等特殊符号,而今天这份则是没有特殊符号的,并且记录数达到了71万且网名没有重复。 分类统计:搞笑网名(20577)、男生网名(

    2024年02月07日
    浏览(44)
  • 编写一个微信小程序,实现表单提交数据到云数据库

    好的。 首先,你需要在微信公众平台中创建一个小程序,并在小程序的后台获取到云开发的相关权限。然后你就可以使用微信小程序开发工具进行开发了。 在页面中创建一个表单,并在表单中添加输入框和提交按钮。 在小程序的 app.js 文件中初始化云开发环境。 在表单的提

    2024年02月07日
    浏览(49)
  • 论文笔记:从不平衡数据流中学习的综述: 分类、挑战、实证研究和可重复的实验框架

    论文:A survey on learning from imbalanced data streams: taxonomy, challenges, empirical study, and reproducible experimental framework 发表:2023年发表在Machine Learning上。 源代码:https://github.com/canoalberto/imbalanced-streams 类不平衡给数据流分类带来了新的挑战。最近在文献中提出的许多算法使用各种数据驱

    2024年02月11日
    浏览(44)
  • 【MySQL 】MySQL 创建数据库, MySQL 删除数据库,MySQL 选择数据库

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 我们可以在登陆 MySQL 服务后,使用 create 命令创建数据库,语法如下: 以下命令简单的演示了创建数据库的过程,

    2024年02月13日
    浏览(92)
  • MySQL数据库:数据库管理系统与安装MySQL数据库

    目录 一、理论 1.数据库管理系统 2.关系型数据库 3.数据库 4.MySQL数据库 5.MySQL部署 二、实验 1.yum安装MySQL 2.编译安装MySQL 3.配置MySQL数据库的Tab补全  三、问题 1.数据库登录报错 2.数据库密码复杂度报错 3.数据库连接报错 四、总结 (1)概念 数据库管理系统(Database Management

    2024年02月12日
    浏览(65)
  • 【MySQL数据库】MySQL数据库管理

    Structure Query Language(结构化查询语言)简称SQL,它被美国国家标准局(ANSI)确定为关系型数据库语言的美国标准,后被国际化标准组织(ISO)采纳为关系数据库语言的国际标准。数据库管理系统可以通过SQL管理数据库;定义和操作数据,维护数据的完整性和安全性。 数据:(data)

    2024年02月08日
    浏览(51)
  • 初识MySQL数据库——“MySQL数据库”

    各位CSDN的uu们你们好呀,小雅兰好久没有更文啦,确实是心有余而力不足,最近学习的内容太难了,这篇博客又是小雅兰的新专栏啦,主要介绍的是一些MySQL数据库的知识点,下面,让我们进入初识MySQL数据库的世界吧 为什么要使用数据库 数据库与数据库管理系统 MySQL介绍

    2024年02月06日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包