实操事务的四大隔离级别以及浅解三大读(脏读、不可重复读、幻读)现象

本文主要是介绍实操事务的四大隔离级别以及浅解三大读(脏读、不可重复读、幻读)现象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.事务的隔离级别
    • 2.事务的隔离级别引发的三大读现象(脏读、不可重复读、幻读)
    • 3.演示事务
      • (1)演示读未提交
      • (2)演示读已提交
      • (3)演示可重复读
        • 关于幻读的理解
      • (4)演示可串行化

1.事务的隔离级别

  • 首先我们先了解一下什么是事务的隔离级别

下面介绍一下事务的四大隔离级别:

  1. 读未提交(READ_UNCOMMITTED):最低隔离级别,允许读到未提交的事务中的数据变更,会导致脏读现象
  2. 读已提交(READ_COMMITTED):Oracle数据库默认隔离级别,允许读到已提交事务的数据,解决了脏读现象,当前事务不能保证想读的数据前后读取一致,也就是不可重复读,这种隔离级别不能解决。
  3. 可重复读(REPEATABLE_READ):MySQL数据库默认隔离级别,事务对同一字段或记录的多次读取结果都是一样的,解决了脏读和不可重复读现象,但是会出现幻读现象。
  4. 可串行化(SERIALIZABLE):事务最高隔离级别,完全遵循得物的ACID特性,所有事物排依次执行,对操作的数据加锁,当前事务未提交时其他事物不能操作。解决了脏读、不可重复读、幻读。

2.事务的隔离级别引发的三大读现象(脏读、不可重复读、幻读)

  • 可能上面的概念有些懵,这脏读、幻读、不可重复读是什么啊?在这里浅浅的解释一下:
  1. 脏读现象:脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,**也就是不存在的数据,这些数据是脏数据。**读到了并不一定最终存在的数据,这就是脏读。例子:事务B的更新数据被事务A读取,但是事务B回滚了,更新数据全部还原,也就是说事务A刚刚读到的数据并没有存在于数据库中。
  2. 不可重复读现象:不可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。事务 A 在某种业务情况下需要多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
  3. 幻读现象:当同一个查询在不同的时间产生不同的行集时,事务中就会出现所谓的幻影问题。例如,如果SELECT执行了两次,但第二次返回的行不是第一次返回的,那么该行就是“幻影”行。

为了更好的了解事务的隔离级别和这些读现象,我们来实时演示一下事务:

3.演示事务

(1)演示读未提交

演示读未提交(READ_UNCOMMITTED):

  1. 可以看到,我们现在的隔离级别是mysql默认隔离级别为RR(可重复读),现在我们修改事务的隔离级别为RU(读未提交)

我们先查看一下当前事务隔离级别:

# 查看当前事务隔离级别
show variables like 'transaction_isolation';

接着我们修改事务隔离级别为RU(读未提交)切记我们设置完事务的隔离级别后,需要将窗口关闭,然后再次打开才会生效!注意测试完后记得改回去哈!

# 设置事务级别为读未提交,这是设置全局的,用完之后记得该回到可重复读哈!
set global transaction isolation level read uncommitted;

  1. 设置完隔离级别后,我们开启两个小黑窗口,分别开启事务,暂且称为事务A和事务B,首先我们查询我的userdb数据库中的tb_user表的数据。
# 开启事务
start transaction;

事务A:

事务B:

  1. 现在我们在事务A中查询id为40的记录,接着我们修改这条记录的年龄为20;

  1. OK,现在我们不要动事务A,跑到事务B这里来查询同一条记录,此时我们的事务A是没有提交的

  1. OK,现在我们回滚事务A,查询数据库中数据
# 回滚事务
rollback;
# 提交事务
commit;

OK,结束显示完毕,可以看到,我们在事务A没有提交的情况下,事务B读到了事务A所修改但未提交的数据,这就是数据库中的读未提交(READ_UNCOMMITTED)隔离级别。

问题:事务B读到了事务A未提交的数据,但是事务A并没有采用这条数据,并将它回滚了,这条数据我们称为脏数据,而事务B读取这条读数据的行为就被称为脏读现象

(2)演示读已提交

演示读已提交(READ_COMMITTED):

  1. OK,我们重新设置mysql数据的隔离级别为读已提交RC,操作和上面差不多我就省略了哈。
set global transaction isolation level read committed;
  1. 现在我们来修改事务A中的数据,还是修改年龄为18

  1. 此时,我们使用事务B查询统一条记录,注意此时事务A是没有提交的。

OK,这就是事务中的读已提交RC的隔离级别,事务B只能读到事务A已提交后的数据,这样避免脏读现象。

问题:就是我事务B在某种业务情况下,要求前后读到的数据要一致,此时当我事务A提交事务后,事务B多次读取到的同一数据前后不一致了,这就是我们所谓的不可重复读现象

(3)演示可重复读

演示可重复读(REPEATABLE_READ):

  1. 修改mysql数据的隔离级别为可重复读
set global transaction isolation level repeatable read;
  1. 重复之前演示读已提交的操作,事务A修改id为40的记录年龄为18(之前修改成20了),事务B去读取,在事务A未提交的情况下;随后事务A提交,事务B再次读取该数据。发现事务B读取的数据都一样,这就是可重复读隔离级别RR

事务A:

事务B:

问题:

但是这种隔离级别还是存在问题,会产生幻读现象。什么是幻读,网上关于这个理解有很多,而我在这里提出自己的理解,我也是个初学者,理解不到位还请见谅。

关于幻读的理解

参考博客:(一文详解脏读、不可重复读、幻读_脏读 幻读 不可重复读_啊啊啊啊啊北的博客-CSDN博客)

这是官方文档解说:The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

当同一个查询在不同的时间产生不同的行集时,事务中就会出现所谓的幻影问题。例如,如果SELECT执行了两次,但第二次返回的行不是第一次返回的,那么该行就是“幻影”行。

我的理解:幻读和不可重复读是有相似之处的,但是还是不一样的。

不可重复读是在同一事务内读到了不同的数据,事务查到的数据前后一致性我不保证,新增的其他数据我不管照查。前一次我查到了A、B,后一次我查到了A、B、C。但是我不保证我前后查出来的A、B数据一致,其他事物修改了A、B提交,我也一并查出来。

而幻读查对于新增的数据就要管一管了。

幻读是在RR隔离级别下,同一事务提交前所多次读取到的同一条件的数据集合是一致的情况下,但是又存在其他事务执行的操作对当前事务的影响是实实在在的,当前事务却感知不到。而当前事务去操作的时候,这份影响又存在,就像幻觉一样,前一次我查询出来A、B,后面有事务插入了C,但是我再次查询时,显示的还是A、B,C查不出来,当我执行插入C的时候却发现插入不了,当我提交事务后,再次执行查询到了C,那么C这行的数据就是“幻影行”。

业务场景:

  1. 现在我有两个事务,事务A和事务B,数据库的隔离级别为可重复读RR
  2. 以我上面表的数据为例(太懒了就不做实操了),现在我的事务A查询数据只有id为39、40两条。
  3. 此时事务B向数据库中插入了一条id为41的数据,并且提交事务。
  4. 事务A不知道事务B插入了一条数据,但是保险起见它又查询了一次,此时它读到的数据还是只有两条。
  5. 现在事务A确信没有其他数据了,所以放心大胆的向数据库中插入了一条id为41的数据,但是却报错了。
  6. 报错的原因是主键重复,好,事务A懵逼了,妈耶大白天遇到“鬼打墙”了,我查出来数据库确实没有这条记录啊,怎么插不进去嘞。

举个例子:云南的朋友应该很好理解,我在野外采了我不知道的菌子(假设有毒的),我拿回去煮了吃了中毒了(开启事务),吃完之后我飘飘欲仙,爽得要死。此时,现在有个人跑过来给了我的腿两闷棍,因为中毒的原因我不知道别人给了我两闷棍,第一时间感受不到痛(当前事务感觉不到,或者感觉是错的),但是当我要去走的时候却发现腿骨折了怎么都走不动(其他事务的影响是实实在在的),吃菌子中毒却让我认为别人并没有打我,我的身体还是好的,诶我明明身体是好的但是却走不了路了怎么回事。等我毒性消失(事务提交)才缓过来我被打了并且立马找他讹十万块,可以带入理解一下幻读。

所以可以进一步理解,引用我上面参考博客里面的话,“幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

(4)演示可串行化

演示可串行化(SERIALIZABLE):

  1. 修改mysql数据的隔离级别为最高级别可串行化
set global transaction isolation level serializable;
  1. 开启事务A,事务B,事务A修改表中数据,id = 39 年龄age为20,修改成功,此时事务B也开始修改这条数据,但是发现修改不了。

事务A:

事务B:

  1. OK,现在事务A提交,我们事务B再次操作这条数据试试看。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3bdr6mgX-1691218471498)(assets/image-20230805144851702.png)]

OK,这就是事务的最高隔离级别可串行化,所有的事务一个一个运行,不可并行。这个隔离级别会在当前事务所操作的数据添加一道行锁,在这个事务里面操作的数据其他事务都操作。解决了三大读问题,该隔离级别完全遵循事务的ACID原则。

  • OK,演示到此结束,初学者的学习,如果有不到位还请见谅,希望帮忙指出,谢谢!

这篇关于实操事务的四大隔离级别以及浅解三大读(脏读、不可重复读、幻读)现象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/187797

相关文章

poj2406(连续重复子串)

题意:判断串s是不是str^n,求str的最大长度。 解题思路:kmp可解,后缀数组的倍增算法超时。next[i]表示在第i位匹配失败后,自动跳转到next[i],所以1到next[n]这个串 等于 n-next[n]+1到n这个串。 代码如下; #include<iostream>#include<algorithm>#include<stdio.h>#include<math.

poj3261(可重复k次的最长子串)

题意:可重复k次的最长子串 解题思路:求所有区间[x,x+k-1]中的最小值的最大值。求sa时间复杂度Nlog(N),求最值时间复杂度N*N,但实际复杂度很低。题目数据也比较水,不然估计过不了。 代码入下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

MySql 事务练习

事务(transaction) -- 事务 transaction-- 事务是一组操作的集合,是一个不可分割的工作单位,事务会将所有的操作作为一个整体一起向系统提交或撤销请求-- 事务的操作要么同时成功,要么同时失败-- MySql的事务默认是自动提交的,当执行一个DML语句,MySql会立即自动隐式提交事务-- 常见案例:银行转账-- 逻辑:A给B转账1000:1.查询

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

C# 防止按钮botton重复“点击”的方法

在使用C#的按钮控件的时候,经常我们想如果出现了多次点击的时候只让其在执行的时候只响应一次。这个时候很多人可能会想到使用Enable=false, 但是实际情况是还是会被多次触发,因为C#采用的是消息队列机制,这个时候我们只需要在Enable = true 之前加一句 Application.DoEvents();就能达到防止重复点击的问题。 private void btnGenerateSh

如何掌握面向对象编程的四大特性、Lambda 表达式及 I/O 流:全面指南

这里写目录标题 OOP语言的四大特性lambda输入/输出流(I/O流) OOP语言的四大特性 面向对象编程(OOP)是一种编程范式,它通过使用“对象”来组织代码。OOP 的四大特性是封装、继承、多态和抽象。这些特性帮助程序员更好地管理复杂的代码,使程序更易于理解和维护。 类-》实体的抽象类型 实体(属性,行为) -》 ADT(abstract data type) 属性-》成

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

MySQL脏读、不可重复读、幻读(虚读)

事务的特性: 原子性:指处于同一个事务中的多条语句是不可分割的。一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K。隔离性:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰持久性:事务一旦提交,就应该被永久保存起来。 事务隔离性问题: 如果不考虑事务的隔离性,会出现以下问题: 脏读:指一个线程中的事务读取到