MySQL:事务的ACID特性隔离级别脏读、不可重复读、幻读、Next-Key锁——场景复现

news2024/9/20 10:47:35

目录

1、什么是事务

2、 事务的ACID特性

2.1 事务的隔离性

3、为什么要使用事务?

4、查看支持事务的存储引擎

5、使用事务

5.1 控制事务

5.1.1 开启事务

5.1.2 关闭事务

5.2 开始一个事务,执行修改后回滚

5.3 开始一个事务,执行修改后提交

5.4 保存点

 5.5 自动/手动提交事务

6、隔离级别

6.1 隔离级别分类

6.1.1 查看隔离级别

6.1.2 设置隔离级别

6.2 READ UNCOMMITTED 【读未提交】

6.2.1 场景复现——“脏读”

6.3  READ COMMITTED 【读已提交】

6.3.1 场景复现——“不可重复读”

6.4  REPEATABLE READ 【可重复读(默认)】

6.4.1 场景复现——“幻读”

6.4.2 场景复现——间隙锁(next-key锁)

6.5 SERIALIZABLE【串行化】


1、什么是事务

事务一般是指要做的或所做的事情。

在计算机术语中,事务是指访问并可能更新‌数据库中各种数据项的一个程序执行单元。

事务结束有两种:

  1. 事务中的步骤全部成功执行时,提交事务。
  2. 如果其中一个失败,那么将会发生回滚。

在事务中,对于修改,只要提交(commit),就可以成功保存;只要回滚(rollback),就可以回到事务之初。


2、 事务的ACID特性

事务中含若干个SQL语句(可以是一组,也可以是一个),事务将这些SQL语句打包为一个整体,在执行的过程中,需满足:

  1. 原子性(Atomicity):是支持事务的数据库中最基本的一个特性。事务中的SQL,要么全部执行成功要么全部执行失败,不会出现只执行一半的情况。如果事务在执行时出现错误,事务就会回滚(Rollback)到事务开始的状态,就像事务没有执行过一样,不会出现只执行一半的情况。
  2. 一致性(Consistency):执行前后,结果“总和”不变。执行完成后,保证数据正确且符合预期。
  3. 隔离性(Isolation):执行时,多个事务之间不能相互干扰。
  4. 持久性(Durability):一旦执行完毕(提交或回滚)后,即刻落盘(永久保存,不会丢失)。

以上这四点在事务的整个执行过程中必须要得到保证,这也就是事务的 ACID 特性。

  • 事务的一致性,是通过原子性、隔离性和持久性来实现的。

2.1 事务的隔离性

由于数据库是一个网络服务,可以同时支持多个客户端进行访问,那么不同的客户端在对同⼀张表中的同一条数据进行修改的时候就可能出现相互影响的情况。为了保证多个客户端之间不能相互干扰和影响,那么事务间就需要隔离起来,这种特性就称为隔离性。

本篇主要讲解事务的隔离性,下文会详细讲解隔离级别。为了帮助大家更好的理解隔离性,这里为大家举个例子。

假设张三的余额中存有1000元,此时,会话1和会话2同时对张三的余额进行扣除100元操作,
正确的余额应该是1000-100-100=800元,但是由于两个会话之间相互干扰(不具备隔离性),导致余额错误:900。

此时,应该考虑在两个会话之间建立隔离性,使两个会话之间不能相互影响,正确结果应该让会话2在会话1的基础上再进行扣除100元的操作。


3、为什么要使用事务?

上文说到,对于数据库而言,两大要素是必须要保证的:

  1. 安全
  2. 效率

上文所讲的索引,是用来提升查询效率的。而事务,就是为了保证数据安全的。

事务的ACID特性,能够保证数据的安全。不论是在网络异常或者服务器宕机的情况下,都能够保证数据安全:修改成功——即刻落盘,永久保存。发生错误——即刻回滚,回到事务之初。


4、查看支持事务的存储引擎

查看MySQL中的存储引擎:show engines;

innoDB是MySQL中支持事务的存储引擎,也是MySQL默认的存储引擎。


5、使用事务

5.1 控制事务

5.1.1 开启事务

开启事务的语法有两种:

  1. begin;
  2. start transaction;

5.1.2 关闭事务

关闭事务分为提交(commit)和回滚(rollback)

  1. commit;//提交当前事务,使修改即刻落盘,永久保存
  2. rollback;//发生错误,撤销修改,回滚(恢复)到事务之初

注意:无论是提交(COMMIT)还是回滚(ROLLBACK),事务都会关闭。

5.2 开始一个事务,执行修改后回滚

事务开始前表中的数据:

开启事务,并在事务中进行插入操作,插入完成后执行回滚rollback操作(同时关闭事务),发现数据回滚到事务之初: 

5.3 开始一个事务,执行修改后提交

 事务开始前表中的数据:

 开启事务,并在事务中进行插入操作,插入完成后执行提交commit操作(同时关闭事务),发现插入的数据被保存: 

注意:

事务提交(commit)后不能再执行回滚(rollback)操作,因为数据提交后就已落盘。

5.4 保存点

在事务执行的过程中我们可以设置保存点,可以回滚到指定的保存点上,将数据恢复到该保存点的状态(不必将数据全部回滚到事务之初)。

 5.5 自动/手动提交事务

在MySQL中,事务是默认自动开启并提交或者回滚的,也就是说,我们写出的每一条SQL语句都是一个事务,且每一个事务中只包含了一条DML语句。

DML语句执行成功则自动提交,如果出现了错误则自动回滚。

查看当前事务是否自动提交,我们可以使用语句:show varibales like 'autocommit';

  1. ON:代表事务开始自动提交/回滚
  2. OFF:代表事务需手动提交/回滚

当然,我们也可以设置事务的提交方式:

# 设置事务⾃动提交
SET AUTOCOMMIT=1; # ⽅式⼀
SET AUTOCOMMIT=ON; # ⽅式⼆
# 设置事务⼿动提交
SET AUTOCOMMIT=0; # ⽅式⼀
SET AUTOCOMMIT=OFF; # ⽅式⼆

注意:

  • 如果使用 start transaction / begin 开启事务,则必须使用commit / rollback 来关闭事务,与是否设置自动提交事务无关。 
  • 手动提交模式下,不用显示开启事务,执行修改操作后,提交或回滚事务时直接使用 commit 或 rollback
  • 已提交的事务不能回滚(数据已落盘)
  • 因为MySQL默认的是自动提交事务,所以即使将autocommit设置为手动,下次启动时,也仍然会恢复为自动提交

6、隔离级别

6.1 隔离级别分类

上文讲到,事务具有隔离性。事务间可以有不同的隔离级别,在这些隔离级别中,有的注重并发性,有的注重安全性,有的并发和安全性适中。在MySQL的innoDB存储引擎中,隔离级别分为以下四种:

  1. READ UNCOMMITTED ,读未提交
  2. READ COMMITTED ,读已提交
  3. REPEATABLE READ ,可重复读(默认)
  4. SERIALIZABLE ,串行化

6.1.1 查看隔离级别

事务的隔离级别分为全局作用域和会话作用域,查看不同作用域事务的隔离级别,可以使用以下的 方式:

# 全局作用域
SELECT @@GLOBAL.transaction_isolation;
# 会话作⽤域
SELECT @@SESSION.transaction_isolation;

使用全局作用域查看的就是所有的会话下的隔离级别,而会话作用域查看的就是仅当前的会话中的隔离级别。

6.1.2 设置隔离级别

# 设置全局事务隔离级别为串⾏化,后续所有事务⽣效,不影响当前事务
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

# 设置会话事务隔离级别为串⾏化,当前会话后续的所有事务⽣效,不影响当前事务,可以在任何时候
执⾏
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

# 如果不指定任何作⽤域,设置只针对下⼀个事务,随后的事务恢复之前的隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

或者

# ⽅式⼀
SET GLOBAL transaction_isolation = 'SERIALIZABLE';
# 注意使⽤SET语法时有空格要⽤"-"代替
SET SESSION transaction_isolation = 'REPEATABLE-READ';

6.2 READ UNCOMMITTED 【读未提交】

READ UNCOMMITTED的隔离级别下,读取数据时不做任何的限制,故此隔离级别具备很高的并发性能,但安全性极低,会出现大量的数据安全问题

例如:事务A对某一数据进行了修改,此时事务A并没有提交,但是事务B却已经读取了这个还没有提交的数据,若事务A对这个数据进行了回滚操作,那么事务B读取的将是一条垃圾数据,毫无意义。

一个事务读取了另一个事务还没有提交的数据,这种情况就叫做“脏读”。 

6.2.1 场景复现——“脏读”

“脏读”现象——复现如下:

因为是全局域的设置,所以其他会话的隔离级别也被修改了:

这时,我们向事务A中插入数据(并不提交),但是事务B却可读取事务A中还未提交的数据:

这种现象就叫做——“脏读”。

6.3  READ COMMITTED 【读已提交】

该隔离级别解决了脏读的问题,只能读取到已提交的数据,但是也出现了不可重复读的问题。

例如:事务A查询了某一条记录后,事务B对这条记录进行了修改了并提交,事务A再次对这条记录进行了查询,发现第一次查询的内容和第二次查询的内容不一致。

这种现象,就叫做“不可重复读”

6.3.1 场景复现——“不可重复读”

“不可重复读”现象——复现如下:

此时,事务B对事务A查询过的记录进行了修改并提交,事务A再次查询该记录得到的内容不一致:

这种现象就叫做——“不可重复读”。

6.4  REPEATABLE READ 【可重复读(默认)】

该隔离级别解决了不可重复读的问题,使得事务A在任何时候读取的数据都是相同的结果,相当于对这条记录上了一把锁,事务B无法对该记录进行修改操作。

但是,该隔离级别出现了“幻读”的问题。

例如:事务A在第一次查询得到了结果集后,事务B进行了记录的增/删操作(例如在记录间的区间间隙中插入新记录),使得事务A再次查询时得到的结果集不同。

这种现象,就叫做“幻读”

但是,innoDB存储引擎中,使用了next-key锁,锁住目标行和之前的间隙(中间有锁,后面没锁),使得其他事务使得无法在记录的间隙中插入新记录,解决了大部分的幻读问题。

注意:

  • 不可重复读,指的是某一条具体的记录发生了改变,两次查询出的这条记录的内容不同。(可以理解为,元素发生了改变)
  • 而“幻读”,指的是结果集发生了改变,使得两次查询得到的结果集不同。(可以理解为,集合发生了改变)

6.4.1 场景复现——“幻读”

“幻读”现象——复现如下:

(由于innoDB对 可重复读 使用了“间隙锁”解决了幻读问题,所以本次仍在 读已提交 的隔离级别下进行演示)

由于事务A在记录的间隙中插入了新数据行,导致事务B在两次相同的查询中,得到的结果集不一致,这种现象就叫做——幻读。

6.4.2 场景复现——间隙锁(next-key锁)

将隔离级别恢复为 可重复读。

把隔离级别设置为REPEATABLE-READ(可重复读)后,在ID的间隙中插入新数据观察现象,如下图所示,在id=5和id=7的间隙中插入id=6的数据行:

innoDB存储引擎使用间隙锁,使得在记录的间隙中无法插入数据,解决了大部分“幻读问题”。

6.5 SERIALIZABLE【串行化】

该隔离级别解决了所有的数据安全问题,所有的事务都是一个挨着一个的执行,一个事务必须等上一个事务执行完之后才能执行。


END

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

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

相关文章

观后感:《中国数据库前世今生》——时代变迁中的数据库崛起

最近观看了《中国数据库前世今生》纪录片,这部影片详细梳理了从1980年代至今,中国数据库技术发展的跌宕历程。作为一名程序员,这部纪录片让我不禁感慨数据库技术的飞速进步,也让我更深入地理解了数据库技术在我们日常生活中的重要…

如何借助项目管理系统实现审批流程的自动化与标准化?

在快节奏的项目申报领域中,繁琐的审批流程往往成为制约项目推进速度的瓶颈。传统的人工审批方式不仅耗时耗力,还容易因人为因素导致审批效率低下、结果不一致等问题。为此,一款能够支持在线审批流程、实现审批自动化与标准化的项目管理系统显…

Canal+RabbitMQ数据同步环境配置

Canal 是阿里巴巴开发的开源工具,主要用于解析 MySQL 的 binlog 日志,从而实现数据同步。Canal 会模拟 MySQL 从库的协议,订阅主库的 binlog,从而获取数据库的变更信息。 将 Canal 解析到的 MySQL 数据库变更消息通过 RabbitMQ 分…

算法打卡 Day34(贪心算法)-分发饼干 + 摆动序列 + 最大子序和

文章目录 理论基础Leetcode 455-分发饼干题目描述解题思路类似题目2410-运动员和训练师的最大匹配数 Leetcode 376-摆动序列题目描述解题思路 Leetcode 53-最大子序和题目描述解题思路 理论基础 贪心算法的本质是选择每一阶段的局部最优,从而达到全局最优。 贪心算…

力扣718-最长重复子数组(Java详细题解)

题目链接:718. 最长重复子数组 - 力扣(LeetCode) 前情提要: 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5…

【CMake】使用CMake在Visual Studio内构建多文件夹工程

一、配置准备 打开VIsual Studio,载入写好的 C M a k e l i s t s . t x t CMakelists.txt CMakelists.txt,在项目中添加以下文件: 创建一个文件夹 f u n c s funcs funcs,里面放入 f u n c . h func.h func.h、 f u n c . c p …

fmql之驱动程序编写(首次)

看了正点原子的zynq系列的Linux开发指南(pdf和视频均有),因此从最简单的程序开始。 驱动程序开发:(第四期视频) 第3.1讲 我的第一个Linux驱动-字符设备驱动框架_哔哩哔哩_bilibili 学习驱动程序编写之前&am…

【论文串烧】多媒体推荐中的模态平衡学习 | 音视频语音识别中丢失导致的模态偏差对丢失视频帧鲁棒性的影响

文章目录 一、多媒体推荐中的模态平衡学习1.1 研究背景1.2 解决问题1.3 实施方案1.4 文章摘要1.5 文章重点1.6 文章图示图 1:不同模型变体在 AmazonClothing 数据集上的初步研究图 2:CKD模型架构的说明图 3:在 Amazon-Clothing 数据集上训练过…

【Linux:共享内存】

共享内存的概念: 操作系统通过页表将共享内存的起始虚拟地址映射到当前进程的地址空间中共享内存是由需要通信的双方进程之一来创建但该资源并不属于创建它的进程,而属于操作系统 共享内存可以在系统中存在多份,供不同个数,不同进…

Qt窗口——QStatusBar

文章目录 状态栏状态栏创建状态栏显示临时消息状态栏添加子控件 状态栏 QStatusBar状态栏是应用程序中输出简要信息的区域,例如画图板下面的区域 我们也可以给程序设置状态栏,表示一些状态。 状态栏创建 使用Qt Creator创建项目的时候,如果…

实现一种可插拔的参数校验

1、概述 仿照mybatis的二级缓存的实现方式,使用“策略模式配置” 的方式实现一个可动态插拔的 参数校验,便于后期扩展。 实现方式也很简单,首先定义一个校验接口,并提供一个校验方法;每种参数校验都是实现 了该校验接口…

前端vue-实现富文本组件

1.使用wangeditor富文本编辑器 工具网站&#xff1a;https://www.wangeditor.com/v4/ 下载安装命令&#xff1a;npm i wangeditor --save 成品如下图&#xff1a; 组件实现代码 <template><div><!-- 富文本编辑器 --><div id"wangeditor">…

Recbole安装指南:步骤详解与常见问题解决方案

1.两种方式&#xff1a; 从Conda安装 如果你还没有安装Conda&#xff0c;可以安装Miniconda或完整的Anaconda。 如果你在中国大陆&#xff0c;我们推荐你使用清华镜像安装Conda。 当你完成Conda的安装后&#xff0c;你可以将RecBole安装在python 3.7的Conda环境中&#xff0…

数据结构之树(下),你真的懂吗?

数据结构入门学习&#xff08;全是干货&#xff09;——树&#xff08;下&#xff09; 1 堆 (Heap) 1.1 什么是堆 堆 (Heap) 是一种特殊的完全二叉树&#xff0c;分为最大堆和最小堆。 最大堆&#xff1a;每个节点的值都大于或等于其子节点的值&#xff0c;根节点是整个堆的…

YOLOv9改进策略【注意力机制篇】| MCAttention 多尺度交叉轴注意力

一、本文介绍 本文记录的是基于MCA注意力模块的YOLOv9目标检测改进方法研究。普通的轴向注意力难以实现长距离交互&#xff0c;不利于捕获分割任务中所需的空间结构或形状&#xff0c;而MCA注意力模块通过构建了两个并行轴向注意力之间的交互&#xff0c;更有效地利用多尺度特…

2.4 卷积2

2.4.2 复正弦波与整体方案 在2.3节中&#xff0c;我们提出了关于复正弦输入的频域输出及其意义的两个问题。为了研究这些问题&#xff0c;我们让一个具有真实脉冲响应 h [ n ] h[n] h[n]&#xff08;即 h Q [ n ] 0 h_Q[n] 0 hQ​[n]0&#xff09;的LTI系统通过输入复正弦…

数据结构(Day16)

一、学习内容 1、有关顺序表的操作&#xff08;功能函数&#xff09; 1、创建顺序表 Plist create_list(){Plist L malloc(sizeof(list)); // 为顺序表分配内存空间if(NULL L){printf("申请空间失败\n");return NULL; // 如果内存分配失败&#xff0c;返回 NU…

RTMP协议在无人机巡检中的应用场景

为什么要用无人机巡检 好多开发者对无人机巡检技术方案&#xff0c;相对陌生&#xff0c;实际上&#xff0c;无人机巡检就是利用无人机对特定区域或设施进行定期或不定期的检查。这种巡检方式相比传统的人工巡检具有显著的优势&#xff0c;包括速度快、覆盖广、风险低、准确性…

Tornado 是一个 Python 异步网络库和 web 框架

Tornado 是一个 Python 异步网络库和 web 框架&#xff0c;它最初由 FriendFeed 开发&#xff0c;后来被 Facebook 收购并开源。Tornado 因其非阻塞的 I/O 操作和优秀的性能而广受欢迎&#xff0c;特别是在需要处理大量并发连接的应用中。Tornado 的底层实现主要依赖于 Python …

神经网络通俗理解学习笔记(0) numpy、matplotlib

Numpy numpynumpy 基本介绍Ndarray对象及其创建Numpy数组的基础索引numpy数组的合并与拆分&#xff08;重要&#xff09;numpy数组的矩阵运算Numpy数组的统计运算numpy中的arg运算numpy中的神奇索引和比较 Matplotlib numpy numpy 基本介绍 numpy 大多数机器学习库都用了这个…