当前位置: 首页 > news >正文

数据库事务中的四大问题:脏读、脏写、不可重复读与幻读详解

数据库事务中的四大问题:脏读、脏写、不可重复读与幻读详解

什么是脏读

定义

事务B读取数据时,读取到的是事务A更新之后,但还未提交的数据。

事务A修改了一条数据,但是还没有提交时,事务B查询到了这条未提交的数据,事务B对这条数据进行一系列业务逻辑操作之后,但事务A因为还没有提交,所以可以随时回滚,这就导致在事务A回滚后,事务B所读取的数据,和实际数据不一致,这种情况就叫脏读。

举例

此时有条数据id为1的数据的balance为 “0” ,事务A要加500,便将其balance更新为 “500”,但在事务A还未提交时,事务B查询了这条数据,得到的是balance为 “500”,然后做了一系列操作之后,事务A回滚了,balance回滚为 “0” ,导致事务B的针对balance为 “500” 做的一系列操作都是白费。

什么是脏写

定义

两个事务同时更新同一条数据时,一个事务A更新数据的是另一个事务B还未提交的数据,此时事务B是可以回滚的,事务B回滚了就会导致出现数据不一致问题。

举例

此时有条数据id为1的数据的balance为 “0” ,事务A要加500,便将其balance更新为 “500” ,
但在事务A还未提交时,事务B要将其加100,就又将其balance更新为 “600” ,并提交了,
此时id为1的数据的balance属性值是 “600” 。
但事务A还没有提交,这就存在一个问题,事务A此时是可以回滚的,并且事务A回滚时,是将其回滚为 “0” 的。
(因为事务A更新数据时,是记录更新前的数据 “0” 到undo日志里)
这就导致事务B的数据更新是更新了个寂寞,这种情况就叫脏写。

什么是不可重复读

定义

在同一个事务中,两次读取同一条数据,因为受到其他事务的影响,而出现两次的结果不一致的情况,就叫不可重复读。

举例

此时有条数据id为1的数据的balance为 “0” ,事务B读取这条数据,获取到balance为 “0”,然后去做其他业务操作,但事务还未结束时。事务A要将其更新为500,便将其balance更新为 “500” 。此时如果事务B再次查询这条数据,则会发现他的数据是balance为 “500”,前后两次查询的结果不一致,这种情况就叫不可重复读。

请添加图片描述

幻读

定义

在同一个事务中,用同样的查询SQL语句,多次去执行,每次会发现查到一些之前没看到过的数据,此时就是幻读。

举例

事务B要查询表中所有balance大于 “0” 的数据,第一次查询,发现没有符合条件的数据,此时事务B还没有结束,然后事务A横插一脚,将其中一条数据的的balance更新为了 “500”。事务B再次查询时,就会发现有符合条件balance大于 “0” 的数据了,此时就说明事务B出现了幻读。

请添加图片描述

怎么处理避免这些情况呢?

处理的方式有:加锁、事务隔离、MVCC。

方案一:加锁

想对锁进一步了解可以参考文章 《 MySQL锁机制揭秘:从行锁到表锁,共享锁到排他锁,悲观锁到乐观锁的全面解读 》

针对脏读/脏写/不可重复读

在读取数据时添加共享锁,读取完之后释放共享锁。在更新数据时添加排他锁,事务结束时释放排他锁。

因为加了排他锁,是无法再加共享锁的,也就是存在事务进行写操作的情况下,其他事务不能进行读操作。

而加了共享锁,也是不能再加排他锁的,也就是存在事务进行读操作的情况下,其他事务不能进行写操作。

这样就有效的避免了脏读和脏写的情况。

但是加锁和释放锁的操作会牺牲性能。

针对幻读

针对在多次查询同一个范围数据,得到了之前没有出现的数据这种情况,可以使用加范围锁(间隙锁)去解决。直接锁定这一区间范围的数据,不允许其他事务进行操作,知道本事务结束,释放范围锁(间隙锁)。

方案二:事务隔离

1、未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他事务中更新了,但是还没有提交的数据。

2、提交读(Read Committed):只能读取到已经提交的数据。

3、可重复读(Repeated Read):在同一个事务内,同一查询语句经过多次执行,得到的结果都会和事务第一次指定的查询结果保持一致。这个事务隔离级别是InnoDB的默认隔离级别。

在SQL标准中,这个隔离级别解决了不可重复读问题,但是还会存在幻读情况,但是InnoDB为了解决幻读引入的一种锁机制,叫间隙锁。

4、串行读(Serializable):完全串行化的读,每次读数据都需要获得表级共享锁,读写相互都会阻塞。是一种性能很低的隔离级别。

方案三:MVCC

通过多版本并发控制机制的undo日志和ReadView机制来解决这些问题。

详情可看 《 MVCC机制解析:提升数据库并发性能的关键 》

关注我,我将持续输出Java常用相关技术文章。
请添加图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【HTTPS】对称加密和非对称加密
  • RocketMQ控制台手动新增主题,报错:clusterName or brokerName can not be all blank
  • 【设计模式-备忘录】
  • Redisson 总结
  • 目前主流语言比较
  • Alluxio EnterpriseAI on K8s 部署教程
  • 探索 Python 的火焰:Fire 库的神秘力量
  • 2016年国赛高教杯数学建模A题系泊系统的设计解题全过程文档及程序
  • 前端开发——(1)使用vercel进行网页开发
  • 标准库标头 <bit>(C++20)学习
  • 【在Linux世界中追寻伟大的One Piece】NAT|代理服务|内网穿透你会吗?
  • 从零开始学习Linux(14)---线程池
  • python有main函数吗
  • 后端-navicat查找语句(单表与多表)
  • NLP 文本匹配任务核心梳理
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • 2017-09-12 前端日报
  • javascript 总结(常用工具类的封装)
  • javascript面向对象之创建对象
  • java第三方包学习之lombok
  • k8s 面向应用开发者的基础命令
  • MYSQL 的 IF 函数
  • PV统计优化设计
  • tensorflow学习笔记3——MNIST应用篇
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • Vue2 SSR 的优化之旅
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 深度解析利用ES6进行Promise封装总结
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ​水经微图Web1.5.0版即将上线
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #QT(智能家居界面-界面切换)
  • #数据结构 笔记三
  • (02)Unity使用在线AI大模型(调用Python)
  • (152)时序收敛--->(02)时序收敛二
  • (4)logging(日志模块)
  • (6)STL算法之转换
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (十六)、把镜像推送到私有化 Docker 仓库
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一)、python程序--模拟电脑鼠走迷宫
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • ****三次握手和四次挥手
  • .NET 服务 ServiceController
  • .NET 某和OA办公系统全局绕过漏洞分析