MySQL中的事务隔离全详解
第一部分:MySQL事务的特性与并行事务引发的问题
1. 什么是事务及其四大特性(ACID)?
事务(Transaction)是数据库操作的基本单位,它将一组操作组合在一起,以确保这些操作作为一个整体被执行。如果事务中的某个操作失败,所有的更改都会回滚(撤销),保证数据的完整性和一致性。
事务的四大特性,通常用 ACID(Atomicity, Consistency, Isolation, Durability)来表示:
-
原子性(Atomicity)
- 定义:事务是一个不可分割的整体,要么全部执行,要么全部不执行。
- 举例:银行转账时,假设从账户 A 转账 100 元到账户 B,包括两个操作:
- 从 A 减少 100 元。
- 向 B 增加 100 元。
如果任意一个操作失败,整个事务都必须回滚,确保账户余额不会出现错误。
-
一致性(Consistency)
- 定义:事务执行前后,数据库都必须保持一致的状态。这意味着,所有事务必须从一个有效的数据库状态转到另一个有效的状态。
- 举例:假设 A 和 B 的账户总余额为 1000 元,无论转账操作发生何种中断,事务的完成后,总余额必须仍然是 1000 元。
-
隔离性(Isolation)
- 定义:多个事务并发执行时,一个事务的执行不能受到其他事务的干扰。每个事务就像独立运行在数据库中一样,其执行过程对其他事务是不可见的。
- 举例:如果 A 向 B 转账时,另一个事务查询账户 B 的余额,必须等到转账事务完成后才能看到更新后的数据,否则查询的结果可能不准确。
-
持久性(Durability)
- 定义:事务一旦提交,其所做的更改就会永久存储在数据库中,即使系统发生故障也不会丢失。
- 举例:如果银行系统发生断电,但 A 转账给 B 的操作已经提交,那么重启后,转账操作仍然有效,数据不会丢失。
2. 并行事务可能引发的问题
在并发环境中,多个事务同时操作数据库,可能导致以下问题:
-
脏读(Dirty Read)
- 定义:一个事务读取了另一个事务未提交的数据。
- 场景:
- 事务 A 修改了账户 B 的余额,将其从 500 元改为 300 元,但尚未提交。
- 事务 B 读取了账户 B 的余额为 300 元。
- 如果事务 A 回滚,账户 B 的余额又恢复到 500 元,此时事务 B 的读取结果就不正确了。
-
不可重复读(Non-Repeatable Read)
- 定义:一个事务在两次读取同一数据时,发现数据不一致,数据被其他事务修改了。
- 场景:
- 事务 A 查询账户 B 的余额,第一次读到 500 元。
- 事务 B 修改账户 B 的余额为 300 元并提交。
- 事务 A 再次读取账户 B 的余额,发现变成了 300 元,数据与第一次读取不一致。
-
幻读(Phantom Read)
- 定义:一个事务在读取某个范围的数据时,发现范围内的数据被其他事务插入或删除了,导致前后查询结果不一致。
- 场景:
- 事务 A 查询工资大于 5000 的员工数,第一次查到 5 个员工。
- 事务 B 插入了一名工资为 6000 的新员工并提交。
- 事务 A 再次查询,发现工资大于 5000 的员工变成了 6 个,出现了“幻影”记录。
第二部分:MySQL的事务隔离级别及其实现
为了解决并发事务引发的问题,SQL 标准定义了 四种事务隔离级别,MySQL 也提供了相应的支持。隔离级别由低到高分别是:
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 可序列化(Serializable)
1. 什么是事务隔离级别?
事务隔离级别决定了一个事务能看到其他事务所做更改的程度。隔离级别越高,事务之间的干扰越少,但性能可能受到影响。
MySQL 默认使用的存储引擎 InnoDB 实现了所有隔离级别,通过锁机制和多版本并发控制(MVCC)来实现隔离。
2. 四种隔离级别的详细介绍
1. 读未提交(Read Uncommitted)
- 定义:一个事务可以读取其他事务尚未提交的更改。
- 问题:
- 存在脏读问题。
- 不可重复读和幻读问题仍然存在。
- 场景:
- 事务 A 修改某记录,将余额从 500 改为 300,但未提交。
- 事务 B 读取该记录时,余额显示为 300。
- 如果事务 A 回滚,事务 B 看到的数据就是错误的。
优缺点:
优点是并发性能高,缺点是数据不可靠。适用于对事务一致性要求极低的场景。
2. 读已提交(Read Committed)
- 定义:一个事务只能读取到其他事务已提交的数据。
- 问题:
- 解决了脏读问题。
- 不可重复读和幻读问题仍然存在。
- 场景:
- 事务 A 修改记录,将余额从 500 改为 300,但未提交,事务 B 无法看到此更改。
- 事务 A 提交后,事务 B 再读取该记录,看到余额为 300。
优缺点:
数据一致性较高,适用于大多数应用场景。Oracle 数据库默认使用此级别。
3. 可重复读(Repeatable Read)
- 定义:在一个事务中多次读取相同数据时,结果始终一致,即使其他事务修改了数据。
- 问题:
- 解决了脏读和不可重复读问题。
- 但幻读问题仍然存在。
- 场景:
- 事务 A 查询某记录,第一次读取余额为 500。
- 事务 B 修改该记录的余额为 300 并提交。
- 在事务 A 中再次读取余额,结果仍为 500,保持一致。
优缺点:
通过 MVCC 技术解决不可重复读问题,InnoDB 默认使用此级别。
4. 可序列化(Serializable)
- 定义:通过强制事务按顺序执行,确保完全隔离。
- 问题:
- 解决了脏读、不可重复读和幻读问题。
- 并发性能最低。
- 场景:
- 事务 A 查询工资大于 5000 的员工数。
- 事务 B 插入一名工资为 6000 的新员工,必须等待事务 A 提交后才能执行。
优缺点:
完全隔离,数据一致性最强,但性能开销大,适合高要求的金融场景。
3. 隔离级别对并发问题的解决情况
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(RU) | √ | √ | √ |
读已提交(RC) | × | √ | √ |
可重复读(RR) | × | × | √ |
可序列化(S) | × | × | × |
4. MySQL 隔离级别的实现细节
MySQL 的 InnoDB 存储引擎通过以下机制实现隔离级别:
-
锁机制
- 行级锁:对单行记录进行加锁,减少锁冲突,提高并发性能。
- 间隙锁(Gap Lock):锁定索引范围,避免幻读问题。
-
MVCC(多版本并发控制)
- 在可重复读隔离级别下,使用 MVCC 技术为每个事务提供“时间点快照”,避免读取到其他事务的修改。
第三部分:事务隔离级别的性能影响、实际使用场景及实现方式
在选择事务隔离级别时,我们需要综合考虑数据一致性和系统性能,并了解每种隔离级别的具体实现原理。下面逐步展开分析:
1. 隔离级别的性能影响
事务隔离级别从低到高,对性能的影响逐渐增大:
-
读未提交(Read Uncommitted)
- 性能最高,因为不需要对数据加锁或者版本控制。
- 缺点是数据一致性最低,可能会读到未提交的临时数据,适合对数据准确性要求极低的场景(如临时报表统计)。
-
读已提交(Read Committed)
- 性能较高,仅使用短时间锁定,读取已提交数据,减少了脏读问题。
- 缺点是仍可能存在不可重复读和幻读问题,适用于 OLTP(在线事务处理)系统,例如大部分电商订单场景。
-
可重复读(Repeatable Read)
- 性能中等,通过 MVCC 技术避免不可重复读问题。
- 会引入间隙锁(Gap Lock)防止幻读,这可能导致更多锁争用,适合对数据一致性要求较高的业务场景,例如库存管理。
-
可序列化(Serializable)
- 性能最低,因为事务是串行执行的,需要加锁或控制访问范围,可能会导致大量事务等待。
- 适合高一致性需求的场景,例如金融转账、证券交易。
2. 实际使用场景建议
-
读未提交(RU)
适用于日志分析、临时数据汇总等场景,这些场景对数据的最终一致性要求不高。 -
读已提交(RC)
推荐作为通用隔离级别,适用于电商、社交平台等对性能和一致性均衡要求的场景。 -
可重复读(RR)
适用于需要保证多个查询结果一致的场景,例如库存查询或长时间事务操作。 -
可序列化(S)
使用场景较少,适用于需要严格一致性且并发量低的场景,如银行核心账户系统。
3. 四种隔离级别的实现方式
在 MySQL 中,隔离级别通过 锁机制 和 MVCC(多版本并发控制) 实现:
1. 读未提交(Read Uncommitted)的实现
- 实现机制:
- 不加锁,直接读取最新数据,即使这些数据未提交。
- 数据的可见性完全依赖于修改的事务状态,因此可能导致脏读。
2. 读已提交(Read Committed)的实现
- 实现机制:
- 读取数据时,事务只访问已经提交的版本。
- 使用短时锁(读锁)来保证读取的数据已经提交,避免脏读。
- MVCC 机制:为每个事务维护一个快照,读取时仅访问在事务启动时已经提交的数据版本。
3. 可重复读(Repeatable Read)的实现
- 实现机制:
- 使用 MVCC 技术,保证在一个事务内读取到的所有数据版本一致。
- 为了避免幻读问题,InnoDB 在范围查询时引入 间隙锁(Gap Lock),锁定数据范围,阻止其他事务插入新数据。
- 例子:
- 如果查询“工资 > 5000 的记录”,事务会锁住满足条件的记录以及索引范围,其他事务不能在范围内插入新记录。
4. 可序列化(Serializable)的实现
- 实现机制:
- 使用读写锁(Shared/Exclusive Lock)强制事务串行化。
- 事务读取数据时,会加共享锁(S 锁),其他事务无法修改;事务写入数据时,会加排他锁(X 锁),阻止其他事务读取或修改。
- 执行范围查询时,锁定整个查询范围,完全避免幻读。
相关文章:
MySQL中的事务隔离全详解
第一部分:MySQL事务的特性与并行事务引发的问题 1. 什么是事务及其四大特性(ACID)? 事务(Transaction)是数据库操作的基本单位,它将一组操作组合在一起,以确保这些操作作为一个整体…...

异常--C++
文章目录 一、异常的概念及使用1、异常的概念2、异常的抛出和捕获3、栈展开4、查找匹配的处理代码5、异常重新抛出6、异常安全问题7、异常规范 二、标准库的异常 一、异常的概念及使用 1、异常的概念 异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并…...

SeggisV1.0 遥感影像分割软件【源代码】讲解
在此基础上进行二次开发,开发自己的软件,例如:【1】无人机及个人私有影像识别【2】离线使用【3】变化监测模型集成【4】个人私有分割模型集成等等,不管是您用来个人学习还是公司研发需求,都相当合适,包您满…...
锁-读写锁-Swift
实现一 pthread_mutex_t: ReadWriteLock/Sources/ReadWriteLock at main SomeRandomiOSDev/ReadWriteLock GitHub https://swiftpackageindex.com/reers/reerkit/1.0.39/documentation/reerkit/readwritelock/ // // Copyright © 2022 reers. // // Pe…...

Kafka如何保证消息可靠?
大家好,我是锋哥。今天分享关于【Kafka如何保证消息可靠?】面试题。希望对大家有帮助; Kafka如何保证消息可靠? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka通过多种机制来确保消息的可靠性,主要包…...

5.10【机器学习】
如果FLAG的画,就是已经有模型了,不然就新建一个模型,通过TORCH方法 在训练的时候,如果TRAIN的话就是训练,不然就是预测 forward前向预测出来一个结果,就是1234 在train方法里,进行多轮迭代&am…...

[白月黑羽]关于仿写股票数据软件题目的解答
原题: 对应问题视频: 实现的效果 不同点 实现的作品和原题要求的不同点 题目要求爬虫获取数据,作品中是调库获取所有股票历史数据实时数据使用爬虫的方式爬取指定股票的数据,需要实时更新,我做了修改,改…...

详解LZ4文件解压缩问题
详解LZ4文件解压缩问题 一、LZ4文件解压缩方法1. 使用LZ4命令行工具2. 使用Python库3. 使用第三方工具4. 在线解压工具 二、常见问题及解决方法1. 解压显示文件损坏2. 解压后文件大小异常 三、总结 LZ4是一种快速的压缩算法,广泛应用于需要实时压缩和解压缩大文件的…...
vue项目中单独文件的js不存在this.$store?.state怎么办
在Vue项目中,如果你在单独的文件(比如插件、工具函数等)中遇到this.$store不存在的情况,这通常是因为this上下文不指向Vue实例,或者Vuex store没有被正确地注入到Vue实例中。以下是几种可能的解决方案: 确保…...

Github提交Pull Request教程 Git基础扫盲(零基础易懂)
1 PR是什么? PR,全称Pull Request(拉取请求),是一种非常重要的协作机制,它是 Git 和 GitHub 等代码托管平台中常见的功能,被广泛用于参与社区贡献,从而促进项目的发展。 PR的整个过…...

Java函数式编程【二】【Stream的装饰】【中间操作】【map映射器】【摊平映射器flatMap】
一、Java的Stream流式编程中的中间操作 Java的Stream流式编程中,中间操作是对数据流进行处理的一种方式,这些操作通常返回流对象本身,以便可以链接更多的操作。以下是一些常见的中间操作: filter(Predicate predicate) - 用于通过…...
树莓派明明安装了opencv和numpy,却找不到
当然不止树莓派,配置python环境都可能存在这个问题 可能是因为安装的 numpy 或者 opencv 版本与 Python 的包路径不匹配。下面是问题的常见原因及解决方法:【方法一和二优先考虑】 原因分析 多版本 Python 环境冲突: 树莓派上可能有多个版本…...
numpy.float8不存在;Python中,实现16位浮点数
目录 python中矩阵的浮点数存储 numpy.float8不存在 Python中,实现16位浮点数 实现 float16 关于 float8 python中矩阵的浮点数存储 在Python中,矩阵通常是通过嵌套列表(list of lists)、NumPy数组(numpy.ndarray)或其他类似的数据结构来表示的。矩阵中存储的数值所…...

Redis集群配置 (不使用docker 部署)
1. Redis集群简介 1.1 什么是Redis集群 Redis集群是一种通过将多个Redis节点连接在一起以实现高可用性、数据分片和负载均衡的技术。它允许Redis在不同节点上同时提供服务,提高整体性能和可靠性。根据搭建的方式和集群的特性,Redis集群主要有三种模式&…...
HTML5系列(7)-- Web Storage 实战指南
前端技术探索系列:HTML5 Web Storage 实战指南 🗄️ 致读者:本地存储的新纪元 👋 前端开发者们, 今天我们将深入探讨 HTML5 中的 Web Storage 技术,这是一个强大的本地存储解决方案,让我们能…...

【在Linux世界中追寻伟大的One Piece】读者写者问题与读写锁
目录 1 -> 读者写者问题 1.1 -> 什么是读者写者问题 1.2 -> 读者写者与生产消费者的区别 1.3 -> 如何理解读者写者问题 2 -> 读写锁 2.1 -> 读写锁接口 3 -> 读者优先(Reader-Preference) 4 -> 写者优先(Writer-Preference) 1 -> 读者写者…...

用到动态库的程序运行过程
当我们写好了一段代码然后编译运行后会生成可执行文件,该文件会存在磁盘的当前目录下,而当我们开始运行这段程序时,操作系统(加载器)需要将其从磁盘加载进内存然后执行相关操作,而对于用到动态库的程序&…...

类型转换与IO流:C++世界的变形与交互之道
文章目录 前言🎄一、类型转换🎈1.1 隐式类型转换🎈1.2 显式类型转换🎁1. C 风格强制类型转换🎁2. C 类型转换操作符 🎈1.3 C 类型转换操作符详解🎁1. static_cast🎁2. dynamic_cast&…...
Pytorch使用手册- TorchVision目标检测微调Tutorial的使用指南(专题十二)
这篇教程的目标是对一个预训练的 Mask R-CNN 模型进行微调,应用于 Penn-Fudan 行人检测与分割数据集。该数据集包含 170 张图像,里面有 345 个行人实例,我们将通过这个教程来演示如何使用 torchvision 中的新特性,训练一个面向自定义数据集的目标检测和实例分割模型。 注意…...
人工智能机器学习算法分类全解析
目录 一、引言 二、机器学习算法分类概述 (一)基于学习方式的分类 1. 监督学习(Supervised Learning) 2. 无监督学习(Unsupervised Learning) 3. 强化学习(Reinforcement Learning…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...