脏读、不可重复读、幻读的解决方法

上一篇博客提到了脏读、不可重复读、幻读的含义,也知道了是因为什么情况导致出现的这些问题,这篇博客就带大家一起来了解一下他们的解决办法~

脏读:脏读出现的原因主要是因为一个事务读取了另外一个事务未提交的数据,就可能出现脏读,解决办法可以通过“读已提交”这种形式进行解决。

“读已提交”这种方法会在事务读取数据的时候生成一个全局性的ID,这个ID代表了所有已提交事物的最新状态,Innodb会去检查每一条数据行,如果其中的id信息是否比当前ID小或者相等,且是已经提交的事务,则这个版本信息是可见的,这就保证了当前事务只能读取到在他开始之前且已经提交的数据。

不可重复读:不可重复读主要是因为事务两次读取到的数据不一样,通过MVCC版本控制可以进行解决。

MVCC:翻译过来就是多版本并发控制,通过对每一个数据行添加版本信息,来解决不可重复读的问题,在RR隔离级别下,使用快照读,这种读取方式只会读取数据一次,后续的所有快照读都是用的同一个快照,所以就不会发生不可重复读的问题了。

幻读:幻读主要是因为事务两次读取到的数据行不一致,有种产生了幻觉的感觉,可以通过在RR隔离级别下使用MVCC+间隙锁的方式进行解决,但是这种方法没法完全避免所有幻读情况的发生;

我们刚刚说的在RR隔离级别下,使用的是快照读,读取的是第一次读取到的数据,后续读取的数据都是通过获取第一次快照读读取的数据,所以在一定程度上可以解决部分幻读的情况;然后通过间隙锁的方式,锁住条件内的数据,对于其他事物新增的数据,直接新增失败

MVCC解决幻读

我们知道,在MVCC中有两种读,一种是快照读、一种是当前读。

所谓快照读,就是读取的是快照数据,即快照生成的那一刻的数据,像我们常用的普通的SELECT语句在不加锁情况下就是快照读。

在 RC 中,每次读取都会重新生成一个快照,总是读取行的最新版本。

在 RR 中,快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照。

那么也就是说,如果在RR下,一个事务中的多次查询,是不会查询到其他的事务中的变更内容的,所以,也就是可以解决幻读的。

如果我们把事务隔离级别设置为RR,那么因为有了MVCC的机制,就能解决幻读的问题:

有这样一张表:

CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT,
    gmt_create DATETIME NOT NULL,
    age INT NOT NULL,
    name VARCHAR(16) NOT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB;

INSERT INTO users(gmt_create,age,name) values(now(),18,'Hollis');
INSERT INTO users(gmt_create,age,name) values(now(),28,'HollisChuang');
INSERT INTO users(gmt_create,age,name) values(now(),38,'Hollis666');

执行如下事务时序:

可以看到,同一个事务中的两次查询结果是一样的,就是在RR级别下,因为有快照读,所以第二次查询其实读取的是一个快照数据。

间隙锁与幻读

上面我们讲过了MVCC能解决RR级别下面的快照读的幻读问题,那么当前读下面的幻读问题怎么解决呢?

当前读就是读取最新数据,所以,加锁的 SELECT,或者对数据进行增删改都会进行当前读,比如:

SELECT * FROM xx_table LOCK IN SHARE MODE;

SELECT * FROM xx_table FOR UPDATE;

INSERT INTO xx_table ...

DELETE FROM xx_table ...

UPDATE xx_table ...

举一个下面的例子:

像上面这种情况,在RR的级别下,当我们使用SELECT … FOR UPDATE的时候,会进行加锁,不仅仅会对行记录进行加锁,还会对记录之间的间隙进行加锁,这就叫做间隙锁。

因为记录之间的间隙被锁住了,所以事务2的插入操作就被阻塞了,一直到事务1把锁释放掉他才能执行成功。

因为事务2无法插入数据成功,所以也就不会存在幻读的现象了。所以,在RR级别中,通过加入间隙锁的方式,就避免了幻读现象的发生。
解决不了的幻读

前面我们介绍了快照读(无锁查询)和当前读(有锁查询)下是如何解决幻读的问题的,但是,上面的例子就是幻读的所有情况了吗?显然并不是。

我们说MVCC只能解决快照读的幻读,那如果在一个事务中发生了当前读,并且在另一个事务插入数据前没来得及加间隙锁的话,会发生什么呢?

那么,我们稍加修改一下上面的SQL代码,通过当前读的方式进行查询数据:

在上面的例子中,在事务1中,我们并没有在事务开启后立即加锁,而是进行了一次普通的查询,然后事务2插入数据成功之后,再通过事务1进行了2次查询。

我们发现,事务1后面的两次查询结果完全不一样,没加锁的情况下,就是快照读,读到的数据就和第一次查询是一样的,就不会发生幻读。但是第二次查询加了锁,就是当前读,那么读取到的数据就有其他事务提交的数据了,就发生了幻读。

那么,如果你理解了上面的这个例子,并且你也理解了当前读的概念,那么你很容易就能想到,下面的这个CASE其实也是会发生幻读的

这里发生幻读的原理,和上面的例子其实是一样的,那就是MVCC只能解决快照读中的幻读问题,而对于当前读(SELECT FOR UPDATE、UPDATE、DELETE等操作)还是会产生幻读的现象的。即,在同一个事务里面,如果既有快照读,又有当前读,那是会产生幻读的、

UPDATE语句也是一种当前读,所以它是可以读到其他事务的提交结果的。

为什么事务1的最后一次查询和倒数第二次查询的结果也不一样呢?

是因为根据快照读的定义,在RR中,如果本事务中发生了数据的修改,那么就会更新快照,那么最后一次查询的结果也就发生了变化。

如何避免幻读

那么了解了幻读的解决场景,以及不能解决的几个CASE之后,我们来总结一下该如何解决幻读的问题呢?

首先,如果想要彻底解决幻读的问题,在InnoDB中只能使用Serializable这种隔离级别。

那么,如果想在一定程度上解决或者避免发生幻读的话,使用RR也可以,但是RC、RU肯定是不行的。

在RR级别中,能使用快照读(无锁查询)的就使用快照读,这样不仅可以减少锁冲突,提升并发度,而且还能避免幻读的发生。

那么,如果在并发场景中,一定要加锁的话怎么办呢?那就一定要在事务一开始就立即加锁,这样就会有间隙锁,也能有效的避免幻读的发生。

但是需要注意的是,间隙锁是导致死锁的一个重要根源~所以,用起来也需要慎重。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/887578.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系

在日常开发中,我们常常需要对复杂的 SQL 进行数据血缘分析。 本文重点讨论在具有 * 列的嵌套子查询中建立表和列之间正确关系的挑战。使用 Teradata SQL 代码示例来说明该过程。 本文聚焦于一个别名为 SUBSCRIBER_ 的子查询及其派生的列,这些列在外层查…

无需VPN!大厂力作:免费AI对口型神器登场,让你的视频制作更简单!

大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 (偶尔会因为推荐工具&#xff…

《深度学习》OpenCV 图像拼接 原理、参数解析、案例实现

目录 一、图像拼接 1、直接看案例 图1与图2展示: 合并完结果: 2、什么是图像拼接 3、图像拼接步骤 1)加载图像 2)特征点检测与描述 3)特征点匹配 4)图像配准 5)图像变换和拼接 6&am…

实验3 选择结构

1、计算分段函数的值 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h> int main() {double x,y0;scanf("%lf",&x);if(x<0){printf("error!\n");return 0;}if(0<x&&x<1){ylog10(x);}else if(1<…

缓存数据减轻服务器压力

问题:不是所有的数据都需要请求后端的 不是所有的数据都需要请求后端的,有些数据是重复的、可以复用的解决方案:缓存 实现思路:每一个分类为一个key,一个可以下面可以有很多菜品 前端是按照分类查询的,所以我们需要通过分类来缓存缓存代码 /*** 根据分类id查询菜品** @pa…

Java | Leetcode Java题解之第459题重复的子字符串

题目&#xff1a; 题解&#xff1a; class Solution {public boolean repeatedSubstringPattern(String s) {return kmp(s s, s);}public boolean kmp(String query, String pattern) {int n query.length();int m pattern.length();int[] fail new int[m];Arrays.fill(fa…

54.二叉树的最大深度

迭代 class Solution {public int maxDepth(TreeNode root) {if(rootnull){return 0;}int de0;Queue<TreeNode> qunew LinkedList<>();TreeNode tn;int le;qu.offer(root);while(!qu.isEmpty()){lequ.size();while(le>0){tnqu.poll();if(tn.left!null){qu.offe…

学会这几个简单的bat代码,轻松在朋友面前装一波13[通俗易懂]

大家好&#xff0c;又见面了&#xff0c;我是你们的朋友全栈君。 这个标题是干什么用的? 最近看晚上某些人耍cmd耍的十分开心&#xff0c;还自称为“黑客”&#xff0c;着实比较搞笑.他们那些花里胡哨的东西在外行看来十分nb,但只要略懂一些&#xff0c;就会发现他们的那些十…

论文阅读笔记-A Comparative Study on Transformer vs RNN in Speech Applications

前言 介绍 序列到序列模型已广泛用于端到端语音处理中,例如自动语音识别(ASR),语音翻译(ST)和文本到语音(TTS)。本文着重介绍把Transformer应用在语音领域上并与RNN进行对比。与传统的基于RNN的模型相比,将Transformer应用于语音的主要困难之一是,它需要更复杂的配…

JavaScript 数组方法

数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始)&#xff0c;整个数组用方括号表示。两端的方括号是数组的标志。 var a["a","b","c"]; 除了在定义时赋值&#xff0c;数组也可以先定义后赋值。 var arr[];arr[1]"a"…

Qt_绘图

目录 1、绘图核心类 2、QPainter类的使用 2.1 绘制线段 2.2 绘制矩形 2.3 绘制圆形 2.4 绘制文本 3、QPen类的使用 3.1 使用画笔 4、QBrush类的使用 4.1 使用画刷 5、绘制图片 5.1 测试QPixmap 5.1.1 图片移动 5.1.2 图标缩小 5.1.3 旋转图片 5.1.4 将…

windows10或11家庭版实现远程桌面连接控制

远程协助是一种Windows工具&#xff0c;允许控制者使用鼠标和键盘远程控制接受者的计算机&#xff0c;从某种程度上讲&#xff0c;这也是Win10家庭版无法远程桌面的一个有效替代方案。 步骤1. 在使用Windows远程协助之前&#xff0c;您需要先更改某些设置&#xff0c;右键单击…

封装el-upload组件,用于上传图片和视频

使用环境 vue3element-ui plus 需要根据后端返回结构修改的函数&#xff1a;onPreview onRemove onSuccess 组件使用 基本使用 源代码&#xff1a; <script setup> import AutoUploadFile from /components/auto-upload-file/index.vue function change(urls){console.…

金智维KRPA之Excel自动化

Excel自动化操作概述 Excel自动化主要用于帮助各种类型的企业用户实现Excel数据处理自动化&#xff0c;Excel自动化是可以从单元格、列、行或范围中读取数据&#xff0c;向其他电子表格或工作簿写入数据等活动。 通过相关命令&#xff0c;还可以对数据进行排序、进行格式…

javaScript数组(16个案例+代码+效果图)

目录 1.数组的概念 2.创建数组 1.通过数组字面量创建数组 1.代码 2.效果 2.通过new Array()创建数组 1.代码 2.效果 3.数组的基本操作 1.获取数组的长度 案例:获取数组的长度 1.代码 2.效果 2.修改数组的长度 1.代码 2.效果 4.访问数组 案例:访问数组 1.代码 2.效果 5.遍历数组…

【EXCEL数据处理】000013 案例 EXCEL筛选与高级筛选。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000013 案例 EXCEL筛选与高级筛选。使用的软件&#…

一个真实可用的登录界面!

需要工具&#xff1a; MySQL数据库、vscode上的php插件PHP Server等 项目结构&#xff1a; login | --backend | --database.sql |--login.php |--welcome.php |--index.html |--script.js |--style.css 项目开展 index.html&#xff1a; 首先需要一个静态网页&#x…

【HTML5】html5开篇基础(4)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

React 解释常见的 hooks: useState / useRef / useContext / useReducer

前言 如果对 re-render 概念还不清楚&#xff0c;建议先看 React & 理解 re-render 的作用、概念&#xff0c;并提供详细的例子解释 再回头看本文。 如果对 React 基础语法还不熟练&#xff0c;建议先看 React & JSX 日常用法与基本原则 再回头看本文。 useState useS…

虚拟机 VMware 安装 macOS

macOS 界面 MAC OS IOS下载&#xff1a; amacOS Monterey by Techrechard.comwmacOS Monterey by Techrechard.com 下载&#xff1a;Unlocker-v2.0.1-x64 Mac OS X 虚拟机中更改屏幕分辨率 终端输入命令&#xff1a; sudo defaults write /Library/Preferences/com.apple.w…