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

并发事务~

一、并发事务出现的场景大致可以划分为以下 3 种:

1、读-读:即并发事务相继读取相同的记录。

读取操作本身不会对记录有一毛钱影响,并不会引起什么问题,所以允许这种情况的发生。

2、写-写:即并发事务相继对相同的记录做出改动。

我们前边说过,在这种情况下会发生脏写的问题,任何一种隔离级别都不允许这种问题的发生。所以在多个未提交事务相继对一条记录做改动时,需要让它们排队执行,这个排队的过程其实是通过锁来实现的。

3、读-写:即一个事务进行读取操作,另一个进行改动操作。

这种情况下,主要可能导致以下三类问题(严重性递增):

  • 脏读 (Dirty Read):
    • 问题描述:一个事务 (T1) 读取了另一个未提交事务 (T2) 修改的数据。随后,T2 可能会回滚(撤销修改),导致 T1 读取的数据实际上从未在数据库中有效存在(即“脏”数据)。
    • 危害:T1 基于无效的数据进行了操作,可能导致业务逻辑错误。
    • 示例:T2 更新账户 A 余额为 +100(但尚未提交);T1 读取账户 A 余额为 +100;T2 因为某种原因回滚,账户 A 实际余额未变;T1 基于读到的 +100 余额进行操作出错。
  • 不可重复读 (Non-Repeatable Read):
    • 问题描述:在同一个事务 (T1) 中,多次读取同一行数据(例如SELECT ... WHERE id=1),在 T1 未结束期间,另一个事务 (T2)提交了对该行数据的修改(UPDATE 或 DELETE),导致 T1 前后两次读取的结果不一致。
    • 危害:破坏了一个事务内逻辑一致性的预期。在一个事务里读取同一个东西,值变了。
    • 示例:T1 第一次查询账户 A 余额为 500;此时 T2 提交了对账户 A 的更新,余额变为 400;T1 第二次查询账户 A 余额,发现变成 400 了,与第一次不一致。
  • 幻读 (Phantom Read):
    • 问题描述:在同一个事务 (T1) 中,多次执行相同的范围查询(例如SELECT ... WHERE value > 100),在 T1 未结束期间,另一个事务 (T2)提交并插入 (INSERT) 或删除 (DELETE) 了某些符合该查询条件范围的数据行,导致 T1 前后两次查询得到的行数或结果集发生了变化(即使同一个 id 的值没变)。
    • 危害:破坏了一个事务内逻辑一致性的预期。范围查询的结果集在事务过程中“凭空”多出了或消失了行,如同幻影。
    • 示例:T1 查询所有余额大于 100 的账户,得到 5 条记录;此时 T2 提交了一个新账户的 INSERT,该账户余额为 200;T1 再次查询余额大于 100 的账户,得到 6 条记录。或者 T2 删除了一条记录,第二次查询返回更少的行。

重要区别:                                                                                 

  • 脏读 vs 不可重复读:脏读读取的是未提交的数据;不可重复读读取的是已提交的数据,但同一个行记录的值在事务过程中被其他事务修改了。                                                 
  • 不可重复读 vs 幻读:不可重复读关注的是同一个行记录的值是否被修改或删除;幻读关注的是满足查询条件的行数/结果集是否因插入或删除操作而改变(新的、之前不存在的行“出现”或“消失”)。                                                                               

二、SQL 标准事务隔离级别及其解决的问题

  为了解决读写冲突导致的问题,SQL 标准定义了四种隔离级别,隔离性由低到高,解决的问题也逐步增多:

  • 读未提交 (Read Uncommitted):
    • 最低隔离级别。
    • 可能出现的问题:脏读、不可重复读、幻读。
    • 解决问题:无。它完全不做任何并发控制(除了可能防止某些最极端的损坏如更新丢失),性能最高但数据一致性风险最大。一般不推荐使用。
  • 读已提交 (Read Committed):
    • 大部分主流数据库的默认隔离级别(如 Oracle, PostgreSQL, SQL Server)。注意:MySQL InnoDB 默认是 Repeatable Read,这与标准不同。
    • 可能出现的问题:不可重复读、幻读。
    • 解决问题:脏读。
    • 原理简述:一个事务只能读取到其他事务已经提交的修改。通常通过在每次 SELECT 时获取一个短暂的读锁(或者通过 MVCC,读取当前已提交的最新快照)来实现,读取完成后立即释放锁。
  • 可重复读 (Repeatable Read):
    • MySQL InnoDB 存储引擎的默认隔离级别。
    • 可能出现的问题:
      • SQL 标准定义:幻读。
      • MySQL InnoDB 的实际实现:通过 MVCC 和 Next-Key Locking 机制,基本避免了幻读。这在 MySQL 中是一个重要的特性和优化。
    • 解决问题:脏读、不可重复读(并且在 MySQL InnoDB 中,基本解决了幻读)。
    • 原理简述:在整个事务执行过程中,第一次读取某行数据时会建立一个快照(MVCC),后续对该行的读取都基于这个快照,其他事务提交的 UPDATE 对该事务不可见。同时,为了防止新行插入造成的幻读,会对查询涉及的范围加间隙锁 (Gap Lock) 或 Next-Key Lock。但已提交的其他事务的 INSERT 可能影响该事务中后续的 INSERT/UPDATE 操作(数据行冲突)。
  • 串行化 (Serializable):
    • 最高隔离级别。
    • 可能出现的问题:无(完全隔离,所有问题都解决)。
    • 解决问题:脏读、不可重复读、幻读。
    • 原理简述:通过强制所有事务串行执行来实现(类似于单线程)。具体实现可能是在 SELECT 读取的范围自动加上共享锁 (Shared Lock),或者在涉及写入的冲突时通过锁竞争强制串行。性能开销最大。

三、隔离级别与问题总结表

也就是说:

  • READ UNCOMMITTED隔离级别下,可能发生脏读、不可重复读和幻读问题。
  • READ COMMITTED隔离级别下,可能发生不可重复读和幻读问题,但是不可以发生脏读问题。
  • REPEATABLE READ隔离级别下,可能发生幻读问题,但是不可以发生脏读和不可重复读的问题。
  • SERIALIZABLE隔离级别下,各种问题都不可以发生。
http://www.lryc.cn/news/591113.html

相关文章:

  • Selector的用法
  • 一台显示器上如何快速切换两台电脑主机?
  • Adobe Photoshop:数字图像处理的终极工具指南
  • JavaScript进阶篇——第八章 原型链、深浅拷贝与原型继承全解析
  • 爬虫逆向:一篇文章掌握 Hopper 的详细使用(macOS 和 Linux 反汇编程序:对可执行文件进行静态分析)
  • Alibaba-NLP/WebAgent 项目总结
  • 如何在PyCharm中删除虚拟环境
  • [MRCTF2020]PYWebsite
  • web APIs(更新中)
  • 中兴B860AV5.1-M2_S905L3SB最新完美版线刷包 解决指示灯异常问题
  • 【测试100问】为什么要做接口测试?
  • 大带宽服务器对于高流量网站的作用
  • 2025年6月GESP(C++一级):值日
  • 淘宝获取商品规格接口(item-sku)操作详解
  • 【Modelsim】原理图怎么看?
  • 【后端】.NET Core API框架搭建(8) --配置使用RabbitMQ
  • `@Configuration` 是 Spring 框架中的一个注解
  • Jmeter使用 -1
  • React Native打开相册选择图片或拍照 -- react-native-image-picker
  • php主流框架FastAdmin框架详解以及如何查看版本号和初始安装fastadmin框架-优雅草卓伊凡|大东家
  • Flutter在Android studio运行出现Error: Entrypoint is not a Dart file
  • HikariCP数据库连接池高性能优化实战指南
  • 23种设计模式--#2单例模式
  • git的cherry-pick
  • Py-Clipboard :iOS与Windows互相共享剪贴板(半自动)
  • AI+医疗!VR和MR解剖学和针灸平台,智能时代如何重塑健康未来
  • vue3实现web端和小程序端个人签名
  • [RAG] LLM 交互层 | 适配器模式 | 文档解析器(`docling`库, CNN, OCR, OpenCV)
  • docker安装与简单项目上手
  • 如何实现微信小程序引导组件【添加到我的小程序】+ 附源码