[email protected]数据库读现象详解(脏读、幻读、不可重复读)_ଲ小何&才露煎煎饺的博客-程序员秘密

技术标签: ACID  read  mysql  数据库  DB  sql  

MySQL数据库读现象

一、数据库的读现象

数据库管理软件的“读现象”指的是当多个事务并发执行时,在读取数据方面可能碰到的问题,包括有脏读、不可重复读和幻读

#读现象
    对于一些数据库管理软件会自带相应的机制去解决脏读、不可重复读、幻读等问题,因为这些自带的机制,下述的一些实验现象可能在某一数据库管理软件的默认机制下并不成立,
    即我们并不能在所有数据库管理软件中看到所有的读现象。
    所以此处我们暂且抛开具体的某个数据库管理软件的默认机制的干扰,暂时假设没有附加任何机制为前提,单纯地去理解数据库的读现象

1、脏读(dirty read):读取未提交数据

一个事务读到了另一个未提交事务修改过的数据
在这里插入图片描述
会话B开启一个事务,把id=1的name为武汉市修改成温州市,此时另外一个会话A也开启一个事务,读取id=1的name,此时的查询结果为温州市,会话B的事务最后回滚了刚才修改的记录,这样会话A读到的数据是不存在的,这个现象就是脏读。(脏读只在读未提交隔离级别才会出现)

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据
在这里插入图片描述

【案列详解】

事务一:查询一条记录, id 为 2 的 age 为 18
事务一:查询后,事务二对该条数据进行了 age=22 的更改, 但是没有进行提交
事务一:有进行查询操作, 查询到修改后的记录 age=22
事务二:进行了回滚操作, 记录中就没有了 id=2, age=22 的记录了, 所以, 事务1读到了一条脏数据(也叫无效数据)

在这里插入图片描述

2、不可重复读取 (nonrepeatable read):前后多次读取,数据内容不一致

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。(即不能读到相同的数据内容)

一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。(不可重复读在读未提交和读已提交隔离级别都可能会出现)
在这里插入图片描述
会话A开启一个事务,查询id=1的结果,此时查询的结果name为武汉市。接着会话B把id=1的name修改为温州市(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),此时会话A的事务再一次查询id=1的结果,读取的结果name为温州市。会话B再此修改id=1的name为杭州市,会话A的事务再次查询id=1,结果name的值为杭州市,这种现象就是不可重复读

例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题
在这里插入图片描述

【案列详解】

事务一:查询一条 id=2 的记录
事务二:随之对 id 为 2 的记录进行了更改, 并且进行了提交
事务一:再次查询 id=2 的记录, 发现第二次查询的记录已经发生了改变, 这个就叫做不可重复读

#在基于锁的并发控制中不可重复读现象发生在当执行 select 操作时没有获得读锁(read locks)或者 select 操作执行完后马上释放了读锁; 多版本并发控制中当没有要求一个提交冲突的事务回滚也会发生不可重复读现象

在这里插入图片描述

3、幻读(nonrepeatable read):前后多次读取,数据总量不一致

幻读是不可重复读的一种特殊情况, 当事务没有获取范围锁的情况下执行 select 操作可能会发生幻读现象

一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。(幻读在读未提交、读已提交、可重复读隔离级别都可能会出现)
在这里插入图片描述
会话A开启一个事务,查询id>0的记录,此时会查到name=武汉市的记录。接着会话B插入一条name=温州市的数据(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),这时会话A的事务再以刚才的查询条件(id>0)再一次查询,此时会出现两条记录(name为武汉市和温州市的记录),这种现象就是幻读

一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读
事务一执行了两次相同的查询操作。但是两次操作中间事务二向数据库中增加了一条符合事务一的查询条件的数据,导致幻读在这里插入图片描述

【案列详解】

事务一:读取或修改了指定 where 子句过滤出来的结果集
事务二:插入了一条新记录, 并且该条记录满足 where 子句的过滤条件
事务一:使用相同的查询再次进行检索, 发现看到了事务二刚刚插入的记录, 但刚刚明明已经使用 where 子句过滤修改了这些记录, 就好像"幻觉’'一样, 这对于事务一来说是突然出现的, 这就是幻读

在这里插入图片描述

二、不可重复读与幻读之间的区别

幻读和不可重复读都是指的一个事务范围内的操作受到其他事务的影响
区别:幻读是重点在插入和删除,不可重复读重点在修改

1)#~~不可重复读~~ 是读取了其他事务更改的数据,针对update操作
解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。



2)#~~幻读~~ 是读取了其他事务新增的数据,针对insert与delete操作
解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。

三、事务的隔离级别

MySQL的事务隔离级别一共有四个,分别是读未提交、读已提交、可重复读以及可串行化

MySQL的隔离级别的作用就是让事务之间互相隔离,互不影响,这样可以保证事务的一致性。
隔离级别比较:可串行化>可重复读>读已提交>读未提交
隔离级别对性能的影响比较:可串行化>可重复读>读已提交>读未提交

由此看出,隔离级别越高,所需要消耗的MySQL性能越大(如事务并发严重性),为了平衡二者,一般建议设置的隔离级别为可重复读,MySQL默认的隔离级别也是可重复读

1、读未提交(READ UNCOMMITTED)

在这里插入图片描述在读未提交隔离级别下,事务A可以读取到事务B修改过但未提交的数据。
可能发生脏读、不可重复读和幻读问题,一般很少使用此隔离级别

2、读已提交(READ COMMITTED)

在这里插入图片描述
在读已提交隔离级别下,事务B只能在事务A修改过并且已提交后才能读取到事务B修改的数据
读已提交隔离级别解决了脏读的问题,但可能发生不可重复读和幻读问题,一般很少使用此隔离级别

3、可重复读(REPEATABLE READ)

在这里插入图片描述
在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务B修改的数据。
可重复读隔离级别解决了脏读和不可重复读的问题,但可能发生幻读问题。

提问:为什么上了写锁(写操作),别的事务还可以读操作?
因为InnoDB有MVCC机制(多版本并发控制),可以使用快照读,而不会被阻塞

4、可串行化(SERIALIZABLE)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
各种问题(脏读、不可重复读、幻读)都不会发生,通过加锁实现(读锁和写锁)

在这里插入图片描述
在这里插入图片描述

5、隔离级别的实现原理

使用MySQL的默认隔离级别(可重复读)来进行说明。

每条记录在更新的时候都会同时记录一条回滚操作(回滚操作日志undo log)。
同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。
即通过回滚(rollback操作),可以回到前一个状态的值

四、解决方案

其实,脏写、脏读、不可重复读、幻读,都是因为业务系统会多线程并发执行,每个线程可能都会开启一个事务,每个事务都会执行增删改查操作。
然后数据库会并发执行多个事务,多个事务可能会并发地对缓存页里的同一批数据进行增删改查操作,
于是这个并发增删改查同一批数据的问题,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。

所以这些问题的本质,都是数据库的多事务并发问题

那么为了解决多事务并发带来的脏读、不可重复读、幻读等读等问题,数据库才设计了锁机制、事务隔离机制、MVCC 多版本隔离机制,用一整套机制来解决多事务并发问题

【MySQL解决幻读】

在高并发的情况下,我们要保证数据的一致性和事务与事务之间的隔离性
1)多版本控制(MVCC)
2)Next-Key锁(当前读)

【多版本控制(MVCC)的原理】

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列分别保存了这个行的创建时间,一个保存的是行的删除时间。
这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID

【Next-Key锁(当前读)的原理】

将当前数据行与上一条数据和下一条数据之间的间隙锁定,保证此范围内读取数据是一致的

#Next-Key锁又分为两种:
   1)记录锁(Record Locks):加在索引上的锁,记录锁是 封锁记录,记录锁也叫行锁
         列:SELECT * FROM `test` WHERE `id`=1 FOR UPDATE;
            它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行
  
记录锁、间隙锁、临键锁都是排它锁

   2)间隙锁(Gap Locks):加在索引之间的锁,间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围
   
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_55972781/article/details/118765092

智能推荐

联想 Thinkserver TS250服务器RAID1 重建测试_amrpjbg72002的博客-程序员秘密

1、RAID1状态下,拨掉其中一块硬盘后,RAID1即失效。2、重新插入后,在进行系统后会自动重建*RAID1 提示Rebuild*进入桌面后软件,显示重建进度 软件下载地址:https://passport.cnblogs.com/ResetPassword.aspx?id=da77e182ed454da8840d9f4104a...

linux下的0号进程和1号进程_lyl194458的博客-程序员秘密

系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个linux系统的所有进程也是一个树形结 构。树根是系统自动构造的,即在内核态下执行的0号进程,它是所有进程的祖先。由0号进程创建1号进程(内核态),1号负责执行内核的部分初始化工作及进 行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。随后,1号进程调用execv...

matlab中条件数无穷大报错,matlab求条件数_静待天时的博客-程序员秘密

矩阵求逆 fliplr 矩阵左右翻转 flipud 矩阵上下翻转 rot90 矩阵逆时针方向旋转90度 2.2.3 矩阵特征运算 Matlab语言中矩阵特征计算函数如下: cond() 矩阵条件数 ......(p,A); 29.matlab 提供 roots 函数求多项式的根,roots(p); 30.matlab 中求 f(x),g(x)的卷积 fg=conv(fg)反卷积 f(x)/g(x)...

改变Spring控制台输出图案_「已注销」的博客-程序员秘密

这样每次运行就能看到一次WHT&GX,方法在src/main/resource下面建立一个banner.txt然后去输入自己想要的图案.(也可以去patorjk.com/software/taag/然后复制粘贴)最后运行代码就好...

利用牛顿迭代法求解非线性方程组_用newton法求非线性方程组_albert future的博客-程序员秘密

最近一个哥们,是用牛顿迭代法求解一个四变量方程组的最优解问题,从网上找了代码去改进,但是总会有点不如意的地方,迭代的次数过多,但是却没有提高精度,真是令人揪心!       经分析,发现是这个方程组中存在很多局部的极值点,是用牛顿迭代法不能不免进入局部极值的问题,更程序的初始值有关!       发现自己好久没有是用Matlab了,顺便从网上查了查代码,自己来修改一下!先普及一下牛顿迭

目标检测(Object Detection)_贾世林jiashilin的博客-程序员秘密

目录目标检测(Object Detection)目标检测算法分类?1.Two stage目标检测算法2.One stage目标检测算法目标检测(Object Detection)目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光...

随便推点

R语言零基础自学:1、开始R和R的语法_1||丨r|?r??。。, %_qq_45660901的博客-程序员秘密

注:学习视频的地址阿雷边学边教R语言第1期—使用R和R的语法第1期——开始R和R的语法一、 什么是R语言?通过编程来进行数据分析和作图的工具为统计分析和数据分析而生,进入数据分析行业或领域之必要二、 为什么学R语言?1、 免费的2、 专业的统计分析软件3、 作图能力强4、 对各种平台和数据源的兼容性强三、 开始学习R语言1、 下载、安装R和RstudioR:https://...

遍历一个对象中所有属性所对应的值_weixin_34356138的博客-程序员秘密

和遍历 数组中的每一个元素的方法很类似注意:在遍历数组时 其中的i对应着数组的下标。 转载于:https://blog.51cto.com/11871779/2118074

SSM-Project-Day05-用户管理-功能:用户的信息修改 要求:修改时不显示密码,不影响跟新数据_西轩草诏暇的博客-程序员秘密

功能分析:选中一条记录,对记录进行修改,进入修改页面上级部门的获取角色的勾选获取

支付宝sdk集成过程中报 openssl/asn1.h file not found错误的解决办法_xcp_123的博客-程序员秘密

最近在做集成支付宝sdk,新版支付宝的sdk集成后,有可能会报两种错误,第一种官方文档上有说,一般是base64file not found之类的,这个原因是没有导入foundation框架导致的,导入即可。另一种是如标题所说的 openssl/asn1.h file not found错误,这个也算是挺常见的一种错误,原因是搜索路径没有设置好,解决办法是选择target - build se

C# ArrayList的初始化和常用方法和查找元素_c#arraylist初始化_qq_42675313的博客-程序员秘密

ArrayList的定义和初始化如下:ArrayList的常用方法如下:List.Add(100)---往List数组中添加元素100List.Insert(3,100)---往List索引为3的位置插入100List.InsertRange(3, List01)---往List索引为3的位置插入List01List.Remove(100)---在List中删除值为100的...

Java开发初学者到月薪20k起,分享正确的Java学习路线!_一斤白菜的博客-程序员秘密

有人提到这个水平不止2w,其实工资是跟面试表现有关的,也跟其他综合水平有关,比如你是985,top10,或者研究生学历,也或者懂点node,懂点大数据等等,或者表达能力强,击中面试官痛点都会加分。如果你达到我说的水准,起薪就是2w,有其他优秀的表现还会在这个基础上加分。但纯JAVA方面待遇是比较吻合的。还有SSH真的不是我要黑,2w水平的面试几乎很少问SSH的用法,要问也是问架构和设计原理等。例如mybatis是如何管理session和cache的。spring里面有哪些你熟悉的设计模式,你怎么理解和应用的

推荐文章

热门文章

相关标签