MySQL事务隔离级别详解

news2024/10/9 12:33:02

一、什么是事务

事务(Transaction)是由一系列对数据库中的数据进行访问与更新的操作所组成的一个程序执行单元。

在同一个事务中所进行的操作,要么都成功,要么就都失败。理想中的事务必须满足四大特性,这就是大名鼎鼎的 ACID 特性。

虽然说 ACID 是事务的四大特性,然而并不是所有的事务都满足 ACID 全部特性,比如:对于 Oracle 和 SQL Server 数据库,其默认隔离级别是 Read COMMITTED,就并不是那么严格的满足 I(隔离性)的要求;对于 MySQL 的 NDB Cluster 引擎来说,不满足 D (持久性)的要求。

A(Atomicity)原子性
原子性指的是数据库事务是不可分割的一部分,只有一个事务中的所有操作都成功,这个事务才算执行成功,一旦有一个操作失败,那么其他成功的操作也必须回滚。 以转账 1000 元场景为例,一个转账过程就是一个事务,这个事务主要包括以下两步:

  1. 从 A 账户扣除 1000 元。

  2. 将 B 账户中增加 1000 元。

试想,如果第一步成功了,那么第二步失败了,那就等于 A 的 1000 元钱直接消失了,相信这是任何人都不能接受的事情,相反的,如果第一步失败,而第二步成功,那么就等于 B 账户中凭空多出来了 1000 元。

上面转账的例子中,不管哪一步失败,结局都不是我们所想要的,所以数据库事务才需要保证原子性,要么都成功,要么都失败。

C(Consistent)一致性
一致性指的是在事务开始之前和事务结束之后,数据库的完整性约束都没有被破坏,事务执行的前后都是合法的数据状态。

这句话看起来有点抽象,具体点来说,一个合法的数据库状态包括了以下两种:

  • 数据库自身的完整性约束。比如主键必须唯一,长度必须符合定义。

  • 用户自定义的完整性约束。比如转账功能,无论两个账户之间怎么转账,最后总和应该保持不变。

I(Isolation)隔离性
隔离性就是说每个事务之间的操作应该相互隔离,互不干扰。比如说一个事务提交之前对另一个事务不可见。

D(Durable)持久性
持久性这个概念就比较容易理解了,就是说事务一旦提交成功了,那么就应该是持久的,即使是数据库重启,服务器宕机等情况发生,数据都不会丢失(当然这个不能包括因为地震等自然灾害导致的存储数据的硬盘发生不可逆的损坏)。

二、如何管理事务

可能很多人会说自己都感知不到 MySQL 的事务,其实这是因为 MySQL 事务是默认开启了自动提交的,因此,如果要感知到事务,我们需要关闭自动提交或者显式开启事务。

事务的自动提交

查看当前数据库是否开启了自动提交,可通过以下语句进行查询确认

SHOW VARIABLES LIKE 'autocommit';-- ON表示开启了自动提交
SELECT @@autocommit;-- 1表示开启

如果需要关闭自动提交,也可以通过以下语句来关闭:

SET autocommit='OFF';
SET @@autocommit = 0;

不过需要注意的是,这种修改方式只是 session 级别的,也就是说只在当前会话窗口生效,对其他打开的会话窗口是不生效的。

常用的事务控制语句

如果需要手动管理事务,通常会使用到以下语句:

  • START TRANSACTION 或者 BEGIN:显式的开启事务。需要注意的是在存储过程中只能用 START TRANSACTION开启事务,因为存储过程本来有 BEGIN…END 语法,两者会冲突。

  • COMMIT:提交事务。也可以写成 COMMIT WORK。

  • ROLLBACK:回滚事务。也可以写成 ROLLBACK WORK。

  • SAVEPOINT identifier:自定义保存点,适用于长事务,可以回滚到我们自定义的位置,identifier为自定义的一个唯一标识,只要保证唯一就行。

  • RELEASE SAVEPOINT identifier:删除指定保存点,identifier为自定义的保存点唯一标识,当前语句如果使用一个不存在的保存点时,会直接报错。

  • ROLLBACK TO [SAVEPOINT] identifier:回滚到指定保存点。

COMMIT 和 COMMIT WORK 的区别

这两个语句都能提交一个事务,在某些情况下是等价的,但是它们的执行效果并不完全是相同的。其区别就在于提交事务之后的操作,同样的还有 ROLLBACK 和 ROLLBACK WORK,而控制这两者之间的区别可以通过变量 completion_type 来控制:

SHOW VARIABLES LIKE '%completion_type%';

得到如下结果:
在这里插入图片描述completion_type 总共有三种类型:

在这里插入图片描述

接下来我们演示一下第三种情况,因为这种情况是最直观能看出区别的一种表现形式。

SET completion_type=2;-- 设置 completion_type 为 2
begin;-- 开启事务
INSERT INTO user_job VALUES (40,'CE0',11);-- 插入一条语句
commit work;-- 提交事务,并同时断开当前连接
select * from user_job;-- 查询

执行完 commit work 之后,数据库连接将会被断开,所以我们后面再执行查询语句,会提示重新连接:

在这里插入图片描述
从上图中可以看到,当执行完 commit work 之后继续执行 select 查询出现了一个自动连接,这就说明了在 commit work 之后连接已经被断开了。

事务的分类

从事务的理论角度来说,我们可以把事务分为以下五大类:

  • 扁平事务

  • 带有保存点的扁平事务

  • 链事务

  • 嵌套事务

  • 分布式事务

下面我们就一一来介绍下这五种事务的区别。

扁平事务
扁平事务是最简单也是最常用的一种事务,这种事务中的所有操作都是原子的,要么全部成功,要么什么都不做,平常我们使用的事务绝大多数都属于扁平事务。

带有保存点的扁平事务
当一个事务过长时,为了避免执行快结束的时候报错导致所有语句都要重新执行,我们可以在指定位置定义好保存点,这样当事务处理到后面报错的时候,我们就可以不需要回滚整个事务,而是回滚到我们自定义好的某一个保存点。

需要注意的是,保存点并不会被持久化,所以在事务提交之前,如果系统发生崩溃,所有的保存点都将消失。

链事务
在提交一个事务之后,释放掉我们不需要的数据,将必要的数据隐式的传给下一个事务。(注意:提交事务操作和开始下一个事务操作是一个原子操作),这就意味着下一个事务能看到上一个事务的结果。

链事务可以看成带有保存点的特殊事务,他们的区别就是带有保存点的事务可以回滚到任意保存点,而链事务中只能回滚到最近的一个保存点(即最新的一个开始事务的点)。

嵌套事务
嵌套事务就是说一个事务之中嵌套另一个事务,事务之间存在父子关系,子事务的提交之后并不生效,需要等到父事务提交之后才会生效。

需要注意的是 MySQL 原生并不支持嵌套事务,但是可以通过保存点模拟嵌套事务,只是说这么模拟的话就没有真正的嵌套事务这么灵活。

分布式事务
分布式事务通常就是在分布式环境下,多个数据库下同时运行不同的扁平事务。多个数据库环境下运行的扁平事务就合成了一个分布式事务。

三、事务的四大隔离级别

未提交读(Read Uncommitted)

未提交读简称:RU,表示一个事务可以读取到其他事务未提交的数据,这种也叫做脏读。未提交读是最低的隔离级别,等于没有隔离,基本上没有数据库会使用这个级别。

未提交读产生的脏读到底是什么问题呢?我们来看下面这幅图:

在这里插入图片描述
左边是事务 1,右边是事务 2,整个执行过程如下:

  1. 事务 1 先执行一次查询,查到 id 为 1 的数据 job_name=CTO。

  2. 事务 2 开启,并执行了一句更新操作,id=1 这条数据中的 job_name 由 CTO 改成了 CEO。

  3. 接下来事务 1 又进行了一次查询(此时事务 2 尚未提交),这时候查出来了 id=1 的数据中 job_name=CEO。

  4. 事务 2 执行 rollback 语句进行回滚,也就是说事务 2 回滚之后,那么 job_name 其实还是CTO,并没有被改变,但是事务 1 却读到了 CEO,这就是脏读。

已提交读(Read Committed)

已提交读简称:RC。表示一个事务只能读取到其他事务已提交的数据(已提交读是 Oracle 和 SQL Server 数据库默认的隔离级别)。就是说在一个事务里面,执行同样的查询,会出现两次不一样的结果。这种隔离级别解决了未提交读产生的脏读问题,但是会出现不可重复读的问题。

什么是不可重复读?还是看上面那个例子,假设事务 2 更新之后马上就提交,然后事务 1 第二次查询查出来的结果job_name=CEO,但是这次就不算是脏读了,原因是事务 2 提交了,并没有发生回滚,这种就叫不可重复读。

而之所以这种称之为不可重复读,就是因为事务 1 中前后两次相同的查询(同一个事务)的数据得到了不一样的结果。

在这里插入图片描述

可重复读(Repeatable Read)

可重复读简称 RR。这种隔离级别解决了不可重复读问题(有时候一个事务中出现不可重复读会影响到系统),就是说在同一个事务中,不管在任何时候执行相同的查询语句,结果都是一样的(对于如何实现可重复读我们在稍后介绍)。

可重复读的隔离级别虽然解决了不可重复读的问题,但是这种级别会出现幻读问题

什么是幻读?请看下面这个例子(原来演示的 user_job 表中有三列,下图中为了方便只画了两列):

在这里插入图片描述
上面图形中,事务 1 进行了一个范围查询,第一次只能查出一条记录,这时候事务 2 来插入了一条数据,然后事务 1 再次执行同一个查询,这时候就能查出来两条记录,也就是多了一条,给人一种幻觉,所以称之为幻读。

说到这里,可能有人就有疑问了,因为感觉不可重复读和幻读都是读取到已提交事务的结果,好像没什么区别?确实如此,不可重复读和幻读本质上是一样的,但是不可重复读针对的是更新和删除操作,而幻读仅针对插入操作。

串行化(Serializable)

这种是隔离的最高级别,也就是说所有的事务都是串行执行的,也就不存在并发事务,脏读,可重复读和幻读问题自然也就没有了。

四种隔离级别对比

不同的隔离级别可以解决不同的问题,大致如下图:
在这里插入图片描述

四、事务隔离方案之 LBCC

LBCC(Lock Based Concurrency Control),基于锁的并发控制。这种方案的实现就是当一个事务去读取一条数据的时候,就上锁,不允许其他事务来操作,很明显,如果说所有的地方都直接加锁,那么当读多写少的场景时这种方案可能会影响到操作效率。

加锁去查询数据时,可以保证任何时候查询到的语句都是最新的,所以这种查询方式也称之为当前读

五、事务隔离方案之 MVCC

MVCC(Multi Version Concurrency Control),多版本的并发控制。当修改数据的时候,可以为这条数据创建一个快照,后面就可以直接读取这个快照。

可重复读的实现方式正是基于 MVCC 控制的,而 MVCC 模式下,查询的数据是从快照中读取,所以也被称之为快照读

MVCC实现原理

在 InnoDB 中,为了实现 MVCC 机制,其内部为每一行添加了两个隐藏列:DB_TRX_ID 和 DB_ROLL_PTR。

  • DB_TRX_ID:事务 ID ,长度为 6 字节,用来存储插入或更新语句的最后一个事务的事务 ID。

  • DB_ROLL_PTR:回滚指针,长度为 7 字节。回滚指针指向写入回滚段(undo log)的记录,读取记录的时候会根据指针去寻找undo 段中的记录。

在 InnoDB 存储引擎中,每个事务开启时就会去申请一个事务 ID,然后在创建视图瞬间,InnoDB 又会在其内部为每个事务构造一个数组,用来保存当前正在活跃(启动了但还没提交)的所有事务 ID。
在这里插入图片描述
上图中,未提交事务是一个数组(黄色区域),那么这三块区域都是如何产生的呢?

  1. 假设当前数据库中已提交的事务只有一个,事务 id=1,而假设此时有一个事务 2 已创建,但是没有提交。

  2. 此时我们又开启了一个事务,那么这时候新开启的事务就会申请一个 id=3。

  3. 这时候已提交事务(绿色区域)就是事务 1,未提交事务(黄色区域)就是两个事务,事务 2 和事务 3。

  4. 而假如当前事务 3 在提交之前,又创建了新的事务,比如事务 4,那么事务 4 及之后的事务就会归属于未开始事务部分(红色区域)。

根据上面简单的介绍,我们可以得出低水位和高水位代表的事务 id:

  • 低水位:未提交事务数组内事务 ID 的最小值(比如上面例子中的事务 2)。

  • 高水位:当前快照中已经创建的事务 ID 的最大值 +1(比如上面例子中的最大事务 3,那么高水位就是 4)

数据可见性规则

1.以当前事务创建视图的时刻为准,如果一条数据的事务版本(DB_TRX_ID)是在当前事务创建视图之前生成并提交的,就可见(比如上图中的绿色区域,代表的就是已提交事务或者当前事务自己生成的数据)。

2.如果一条数据的事务版本(DB_TRX_ID)是在当前事务创建视图之后才生成的,就不可见(比如上图中的红色区域)。

3.如果查询到到的数据事务版本(DB_TRX_ID)正好处于黄色区域,就需要分两种情况: a) 如果 db_trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见; b) 如果 db_trx_id 不在数组中,表示这个版本是由已经提交的事务生成的,可见。

其实前面两点都比较好理解,关键是第 3 点不太好理解。同样的,我们也分为两种情况来分析:

  • 第一种情况就是说事务 id
    在未提交数组(黄色区域)中,这就说明当前产生快照的时候,这些事务都还没提交,所以当前事务的整个事务期间都不能看见这些数据。

  • 第二种情况,为什么会出现处于黄色区域而又不在未提交数组中呢?这是因为一旦未提交事务提交之后,会将其从未提交事务数组移除,但是其仍然属于黄色区域,产生这种现象的原因就是申请事务id 的时间和产生快照的时间并不相同。

快照是什么时候产生的

快照的产生方式有两种情况:

  • 手动执行 START TRANSACTION WITH CONSISTENT SNAPSHOT 时会立即产生快照(此时当前事务 id
    就是未提交事务数组中的最大值)。

  • 事务内第一次执行 select 查询语句之后产生快照(此时当前事务 id不一定是未提交事务数组中的最大值,开始事务后,产生快照前的这段时间可能会有其他事务提交,那么这些事务的数据对当前事务也必须可见,这就是上面提到的处于黄色区域而又不在未提交事务数组的情况)。

MVCC 查询示例

下图描述了一个 MVCC 的查询示例:
在这里插入图片描述
下面我们站在事务 2 的角度进行分析:

  1. 假设数据库已经存在一个事务,这时候同时启动了三个事务,事务 id 分别为 2,3,4。

  2. 事务 2 执行一条查询语句,此时会生成一个快照,而此时未提交的事务组成了一个数组 [2,3,4]。

  3. 事务 2 查询到的数据为右边绿色表格数据,经过对比发现 db_trx_id=1,比自己小,说明其是在自己创建事务之前提交的,对自己可见。

  4. 事务 3 也会产生一个视图,修改数据提交之后,数据对应为右边上面的那个表格。

  5. 此时事务 2 再次查询,查询到的是上面的红色表格中数据,此时发现db_trx_id=3,虽然其落在了黄色区域,但是其在未提交事务数组,说明这个事务至少在事务 2产生快照的时候还没提交的,所以不可见,但是事务 3 的更新的时候会在 db_roll_ptr 列插入上一个版本的数据地址,于是事务 2会根据这个指针找上一个版本,找到绿色的数据。

  6. 事务 4 提交。

  7. 事务 2 执行查询,这时候查询到最下面的红色数据,一看 db_trx_id=4 也在未提交数组,于是根据 db_roll_ptr往上找,依次类推,直到找到绿色数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/135749.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8种专坑同事的 SQL 写法,性能降低100倍,不来看看?

今天给大家分享几个SQL常见的“坏毛病”及优化技巧。 SQL语句的执行顺序: 1、LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般 DBA 想到的办法是在 type、 name、 create_time 字段上…

第二章:Swagger2

目录 背景介绍 什么是Swagger2 常用注解 SpringBoot整合Swagger2 生产环境下屏蔽Swagger2 修改Swagger2配置类 修改application.yml 使用maven package打包测试 运行测试 背景介绍 在团队开发中,一个好的 API 文档不但可以减少大量的沟通成本,还…

Linux系统的进程管理

文章目录Linux系统的进程管理1.查看进程2.父进程3.终止进程4.进程树Linux系统的进程管理 在LINUX中,每个执行的程序都称为一个进程。每一个进程都分配一个ID号(pid,进程号) 每个进程都可能以两种方式存在的。前台与后台,所谓前台进程就是用户目前的屏幕…

Vulnhub 靶场 Earth

通关方案:https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html 思路流程: 1. 信息收集 nmap扫描发现开了22端口和两个web端口(80和443)。 注意这里信息收集到到位,获取的信息多一些。 使用nmap默认脚…

常见的降维技术比较:能否在不丢失信息的情况下降低数据维度

本文将比较各种降维技术在机器学习任务中对表格数据的有效性。我们将降维方法应用于数据集,并通过回归和分类分析评估其有效性。我们将降维方法应用于从与不同领域相关的 UCI 中获取的各种数据集。总共选择了 15 个数据集,其中 7 个将用于回归&#xff0…

电子招标采购系统源码—互联网+招标采购

​ ​ 智慧寻源 多策略、多场景寻源,多种看板让寻源过程全程可监控,根据不同采购场景,采取不同寻源策略, 实现采购寻源线上化管控;同时支持公域和私域寻源。 询价比价 全程线上询比价,信息公开透明&#x…

Kong动态负载均衡与服务发现

Kong动态负载均衡一、背景二、通过docker 安装 Kong三、分布式API网关存在的意义四、Kong 的相关特性五、Kong 体系结构六、Kong 工作流程七、从 nginx 配置到 Kong 配置7.1、Kong 核心四对象7.2、四对象关系八、插件机制九、Kong 网关插件十、使用konga10.1、实现一个负载均衡…

sklearn预测评估指标计算详解:准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1score

目录 前言 一、准确率 二、精确率 三、召回率 四、F1-score 点关注,防走丢,如有纰漏之处,请留言指教,非常感谢 前言 很多时候需要对自己模型进行性能评估,对于一些理论上面的知识我想基本不用说明太多&#xff0…

工具及方法 - 项目管理工具ProjectLibre

这个项目管理工具是开源和免费的,可以作为微软Project工具的平替。官网是 http://www.projectlibre.org 。 下载: ProjectLibre - Project Management download | SourceForge.net 当前的最新版本是2021-01-08的1.9.3版本,而现在是2022-12月…

路由交换网络技术,交换机基础入门及相关特性介绍

一、交换机:工作在数据链路层 ,转发数据帧 HUB所有接口再同一个冲突域,交换机每个接口都属于一个冲突域 交换机功能: 1、学习 2、转发 3、泛洪 4、丢弃 二、学习MAC地址及转发 MAC地址表项默认老化时间300秒。如果在300秒之内收到同一主机从同一接口发来的帧,老化时…

web3:区块链Blockchain

在此声明,仅做分享,绝不存在倡导炒币行为 目录区块链概念区块链基础知识交易(Transaction)区块(Block)链(Chain)公私钥区块链存储结构简单理解区块结构Block区块头Merkle根nonce区块链原理区块链架构区块链特点分布式账本—不可篡改性、去中心化非对称加…

ThinkPHP5之SQLI审计分析(一)

说明 该文章来源于徒弟lu2ker转载至此处,更多文章可参考:https://github.com/lu2ker/ 文章目录说明0x00 测试代码做了什么?0x01 调用链分析0x02 分析最内层调用的处理0x03 分析上一层调用的处理0x04 Payload构造Time:8-31 影响版…

pyTorch入门(六)——实战Android Minist OpenCV手写数字识别(附源码地址)

学更好的别人, 做更好的自己。 ——《微卡智享》 本文长度为4239字,预计阅读12分钟 前言 前面几篇文章实现了pyTorch训练模型,然后在Windows平台用C OpenCV DNN推理都实现了,这篇就来看看在Android端直接实现一个手写数字识别的功…

The Open Group亚太区总经理Chris Forde元旦贺词:踔厉奋发、笃行不怠,共赴新未来!

Happy New Year everyone, hope you are enjoying the holiday season, and perhaps planning your New Year’s resolutions. 大家新年快乐!希望此刻您正在享受假期,或在规划自己的新年决心。 Now is the time for me, with you, to say goodbye to 202…

PDF怎么转换成Word?电脑必备的转换工具

电脑上的办公场景可以说是很多样了,而现在线上办公,线上会议,以及线上网课等的发展越来越全面,关于文件的编辑和传输也渐渐需要更多的软件来辅助我们办公。就像是PDF文件格式和Word文件格式这两种常见的格式,想要直接进…

小米路由器 R4A 刷原生 OpenWrt 后的风景

简 述: 继上篇 小米AX6S刷OpenWrt和开启OpenClash 后,手痒难耐,决定把小米路由器4A千兆版(R4A)路由器 给刷个原生的 OpenWrt。 文章目录背景刷成原生 OpenWrt原生 OpenWrt 基础操作开启 WiFiopkg 换源设置中文OpenClash 插件8M 之殇,终结Refe…

JavaSE学习(二)

1.基本数据类型转换 自动类型转换 1.java程序在进行赋值或运算的时候,会将精度小的类型自动转换为精度大的数据类型再进行计算 2.精度大的类型赋值给精度小的类型会报错,反之则会进行自动类型转换 int a4; floata1.1;这样写是错的,因为1.1是…

Uni-app + Vue3 + TS +Vite 创建项目

一、npx 与 npm 区别 npm 都很熟,可是与 npm 如此相似的 npx 是干嘛的呢?我们为甚要介绍 npx ? 由于 uni-app 官方提供创建命令使用的是 npx,所以我们先来了解下 npx 是干什么的?它与 npm 的区别。 npx 是 npm 的高级版本&…

java 出现unreachable statement异常 原因检查

unreachable statement异常: 今天在写代码的过程中,发现有行代码变红线,显示unreachable statement异常,但是代码本身没什么问题,通过查询资料发现其实就是该行代码不可执行的原因,出现该异常共有以下两种…

第三十八章 贪心算法——区间问题(上)

第三十八章 贪心策略——区间相关问题一、什么贪心策略?二、区间问题合集1、思路:2、问题1: 区间选点(1)问题(2)思路和证明a.思路b.证明(3)代码3、问题2:&…