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…...
Linux 35.6 + JetPack v5.1.4@DeepStream安装
Linux 35.6 JetPack v5.1.4DeepStream安装 1. 源由2. 步骤Step 1 安装Jetpack 5.1.4 L4T 35.6Step 2 安装依赖组件Step 3 安装librdkafkaStep 4 安装 DeepStream SDKStep 5 测试 deepstream-appStep 6 运行 deepstream-app 3. 总结3.1 版本问题3.2 二进制help 4. 参考资料 1. …...
图数据库 | 11、图数据库架构设计——高性能图存储架构(下)
在上篇内容中,老夫着重讲了高性能图存储系统的特点,咱们继续往下讲重点——高性能存储架构的设计思路!! 2.高性能存储架构设计思路 首先呢,存储架构以及核心数据结构的设计思路通常围绕如下4个维度来进行:…...
【HTTP】HTTP协议
一个Web Server就是个服务器软件(程序),或者是运行这个服务器软件的硬件(计算机),其主要功能是通过HTTP协议与客户端进行通信,来接收,存储,处理来自客户端的HTTP请求&…...
大数据新视界 -- Hive 基于 MapReduce 的执行原理(上)(23 / 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
SpringBoot源码解析(六):打印Banner
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
【计算机网络】实验6:IPV4地址的构造超网及IP数据报
实验 6:IPV4地址的构造超网及IP数据报 一、 实验目的 加深对IPV4地址的构造超网(无分类编制)的了解。 加深对IP数据包的发送和转发流程的了解。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实验内容 1、了解IPV4地址的构造超网…...
easy excel 生成excel 文件
导包 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.3</version> </dependency> 内容 List<类> limspjreport 值; String fileName sdf.format(new Date()) "-…...
Ajax:回忆与节点
一点回忆 面对我的Ajax学习,实现前后端交互,最开始我采用的使用网络寻找intellij IDEA Ultimate破解方法,然后最终成功,然后按照相关教程配置java ee项目,然后中间又去配置了Tomcat服务器,然后又去学习了一…...
Python+OpenCV系列:Python和OpenCV的结合和发展
PythonOpenCV系列:Python和OpenCV的结合和发展 **引言****Python语言的发展****1.1 Python的诞生与发展****1.2 Python的核心特性与优势****1.3 Python的应用领域** **OpenCV的发展****2.1 OpenCV的起源与发展****2.2 OpenCV的功能特性****2.3 OpenCV的应用场景** *…...
Ubuntu20.04 由源码编译安装opencv3.2 OpenCV
Ubuntu20.04 由源码编译安装opencv3.2.0 获取 opencv 及opencv_contrib源代码 创建目录以存放opencv及opencv_contrib源代码 mkdir ~/opencv3.2.0 cd ~/opencv3.2.0获取opencv源代码并切换到对应tag git clone https://github.com/opencv/opencv.git cd opencv git checkou…...
哪些做图形推理的网站/有什么好的网站吗
请以尽量高效的方法用”*”打印出一个空心正方形,num为边长。 void print_square(int num); #include <stdio.h>int main() {int x,y,num;printf("please input the num:\n");scanf("%d",&num);for(x 0; x < num; x){for(y 0 ;…...
苏州专业网站设计制作公司/推广软文怎么写
本教程使用社区版IntelliJ IDEA 2021.1。 1 AutoImport 自动导入:包、类等,自动删除未使用的包或类,配置功能如图1.1所示。 图1.1 自动导入配置列表1.1 xml变更提示 pom.xml依赖配置文件发生变更后,IDEA自动提示更新依赖&#…...
广州网站建设联系信科海珠/长沙官网优化公司
需要使用百分率,保留2位小数,其实只用round就可以实现(round(_data,2) ),但是格式不是很工整,对格式要求不严谨的情况下使用round即可,以下是网络搜索到的处理方法: 方法一:使用to_char的fm格式…...
想学学做网站/软文写作什么意思
考古学家有时候遇到一些神秘的门,这些门需要解开特定的谜题才能打开。因为没有其他方法可以打开门,这谜题对我们来说非常重要。在门上有许多磁盘,每个盘子上有一个英文单字在上面。这些盘子必须被安排,使得盘子上的每个单字的第一…...
批发网站有哪些平台/重庆森林壁纸
我们在项目中,经常会碰到这样一种需求,就是让某个程序在某个固定的时间去运行,比如定时备份操作。在Java的J2SE的API中可以很容易做到这一点。让我们需要定时执行的类继承自java.util.TimerTask中的TimerTask类,把需要执行的方法放…...
买域名做网站的坏处/产品如何在网上推广
如何在Linux环境下添加Oracle用户信息呢?下文对Oracle用户信息的添加方法作了详细的介绍,希望可以让您对Oracle用户信息方面有更深的认识。创建一个用户组oinstall:# groupadd oinstall创建一个用户组dba:# groupadd dba创建一个用…...