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

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

文章目录

    • 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

相关文章

Spring中事务的传播机制

一、前言 首先事务传播机制解决了什么问题 Spring 事务传播机制是包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。 事务的传播级别有 7 个,支持当前事务的:REQUIRED、SUPPORTS、MANDATORY; 不支持当前事务的:REQUIRES_NEW、NOT_SUPPORTED、NEVER,以及嵌套事务 NESTED,其中 REQUIRED 是默认的事务传播级别。

LeetCode--220 存在重复元素 III

题目 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。 示例 示例 1:输入: nums = [1,2,3,1], k = 3, t = 0输出: true示例 2:输入: nums = [1,0,1,1], k = 1, t = 2输出: true示例

LeetCode--217 存在重复元素

题目 给定一个整数数组,判断是否存在重复元素。如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 示例 示例 1:输入: [1,2,3,1]输出: true示例 2:输入: [1,2,3,4]输出: false示例 3:输入: [1,1,1,3,3,4,3,2,4,2]输出: true class Solution {p

axios全局封装AbortController取消重复请求

为什么? 问题:为什么axios要配置AbortController?防抖节流不行吗? 分析: 防抖节流本质上是用延时器来操作请求的。防抖是判断延时器是否存在,如果存在,清除延时器,重新开启一个延时器,只执行最后一次请求。节流呢,是判断延时器是否存在,如果存在,直接return掉,直到执行完这个延时器。事实上,这些体验感都不算友好,因为对于用户来说,得等一些时间,尤其是首次请求,不是那么流畅

想让Python序列切片更高效?这些技巧你不可不知!

目录 1、自定义类实现切片 🍏 1.1 实现__getitem__方法 1.2 支持正负索引与步长 2、利用 collections.abc 模块 🧠 2.1 继承MutableSequence类 2.2 重写关键方法 3、使用标准库itertools.slice 🍲 3.1 itertools工具介绍 3.2 slice函数应用实例 4、通过生成器实现动态切片 🌀

PHP生成csv格式Excel,秒级别实现excel导出功能

防止报超内存,兼容中文,兼容科学技术法。 爽。。。。很爽。。。。 /*** 告诉浏览器下载csv文件* @param string $filename*/public static function downloadCsv($data, $filename, $encoding = 'utf-8'){header("Content-type: text/csv");header("Conten

MySQL——数据库级别的外键

仅作了解 方式一:在创建表的时候,增加约束(较复杂) CREATE TABLE IF NOT EXISTS grade(`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',`gradename` VARCHAR(50) NOT NULL COMMENT '年级名字',PRIMARY KEY(`gradeid`) )ENGI

分布式事务的解决方案(一)

前言应用场景 事务必须满足传统事务的特性,即原子性,一致性,分离性和持久性。但是分布式事务处理过程中, 某些场地比如在电商系统中,当有用户下单后,除了在订单表插入一条记录外,对应商品表的这个商品数量必须减1吧,怎么保证? 在搜索广告系统中,当用户点击某广告后,除了在点击事件表中增加一条记录外, 还得去商家账户表中找到这个商家并扣除广告费吧,怎么保证? 一 本地事务 以用户A

java同步锁以及级别升级的理解

首先简单说下先偏向锁、轻量级锁、重量级锁三者各自的应用场景: 偏向锁:只有一个线程进入临界区;轻量级锁:多个线程交替进入临界区;重量级锁:多个线程同时进入临界区。 还要明确的是,偏向锁、轻量级锁都是JVM引入的锁优化手段,目的是降低线程同步的开销。比如以下的同步代码块:   synchronized (lockObject) { // do something } 上述同步代码块

ROS话题通信机制实操C++

ROS话题通信机制实操C++ 创建ROS工程发布方(二狗子)订阅方(翠花)编辑配置文件编译并执行注意订阅的第一条数据丢失 ROS话题通信的理论查阅ROS话题通信流程理论 在ROS话题通信机制实现中,ROS master 不需要实现,且连接的建立也已经被封装了,需要关注的关键点有三个: 发布方(二狗子)订阅方(翠花)数据(此处为普通文本) 创建ROS工程 创建一个ROS工程