还傻傻搞不懂MySQL事务隔离级别么(图文并茂,保证你懂!)

news2025/1/10 2:25:26

本文首发于公众号【看点代码再上班】,欢迎围观,第一时间获取最新文章。

原文:还傻傻搞不懂MySQL事务隔离级别么(图文并茂,保证你懂!)

大家好,我是tin,这是我的第25篇原创文章

上一篇文章已经讲了事务的四大特征,如果不记得了可以再看一下: 昨天去银行转钱,最后怒失300万 。文章中提到,事务是在MySQL引擎中实现的,且我们用得最多的支持事务的引擎是InnoDB。

本文所说的 MySQL 事务也都是指在 InnoDB 引擎下的事务。话不多说,先上一个目录:

  • 一、并行事务会有什么问题?

    1.1 脏写

  • 1.2 脏读

  • 1.3 不可重复读

  • 1.4 幻读

    1.5 区别

    二、事务隔离级别

    2.1 读未提交

    2.2 读已提交

    2.3 可重复读

    2.4 串行化

    三、结语

一、并行事务会有什么问题?

在讲事务隔离级别之前,我们先想一下,如果有多个事务并行执行,MySQL数据最终会有什么问题?

可以说,事务的存在都是为了防止并发问题,我们的MySQL数据库可以同时接受多个client连接,即支持同时多个事务处理,当多个事务同时进行的时候,可能会出现以下等问题:

脏写(dirty write)

脏读(dirty read)

不可重复读(non-repeatable read)

幻读(phantom read)

 

1.1 脏写

脏写 (dirty write),直白说就是两个事务同时更新一行数据,事务A回滚把事务B的值覆盖了,实质就是两个未提交的事务互相影响。

举个例子, 现在有一张表:

CREATE TABLE `bank_balance` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_name` varchar(45) NOT NULL COMMENT '用户名',
  `balance` int NOT NULL DEFAULT '0' COMMENT '余额,单位:人民币分,比如100表示人民币1元,默认是0',
  `wealth` tinyint NOT NULL DEFAULT '0' COMMENT '富有程度,0:贫穷,1:富有',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_bank_balance_user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

表中有一行id=3 且 user_name=Tom的记录:

mysql> select id,user_name,balance from bank_balance where user_name = 'Tom';
+----+-----------+---------+
| id | user_name | balance |
+----+-----------+---------+
| 3 | Tom       |     100 |
+----+-----------+---------+
1 row in set (0.00 sec)

现在有两个事务,事务A和事务B,事务A是给Tom账户余额加100,事务B是给Tom账户余额加200。

在①处,事务A得到的余额是200,事务B得到的余额是300,如果事务B是后更新,那么就覆盖了事务A的值。

在②处,事务 A 和事务B都没有提交的情况下,它们随时都有可能发生回滚,如上图这种情况事务 A 发生了回滚,然后事务B再提交,那么对于事务 B 看到的场景而言,就是自己明明更新了,结果值却还是旧值,这就是 脏写

1.2 脏读

脏读(dirty read)指的是读到了其他事务未提交的数据,未提交意味着可能会回滚,也就是可能最终不会持久化到数据库中。其他事务读到了不会持久化的数据,这就是脏读。

比如下图,如果事务A在①处发生回滚,那么事务B在②处使用的Tom余额值200就是一个过期值,这种就是典型的脏读现象

1.3 不可重复读

不可重复读(non-repeatable read),指的是在同一事务内,相同数据在不同的时刻被读到了不一样的值,它和脏读不一样,脏读是指读取到了其他事务未提交的数据,而不可重复读表示读到了其他事务修改并提交后的值。

比如有两个事务,事务A和事务B,事务A查询Tom账户余额是100,事务B查询Tom账户余额也是100。

接下来,事务A把Tom账户余额更新为200,并提交事务。

当事务B继续读取Tom账户余额的时候,发现Tom账户余额是200了,和之前读取到的不一致,对于事务B而言,这种一个事务内多次读取得到不一样值的现象就称为不可重复读现象

1.4 幻读

幻读(phantom read),主要是是针对数据插入(INSERT)和删除(DELETE)操作来说的。

最经典的是插入的情况。假如现在有两个事务,事务A和事务B。事务A对某些行的内容作了更改,但是还未提交。

比如现在余额表中余额大于0的账户有2条,分别是小克和Tom,他们的富有程度都是贫穷:

mysql> select *from bank_balance where balance > 0;
+----+-----------+-----------+--------+
| id | user_name | balance   | wealth |
+----+-----------+-----------+--------+
|  2 | 小克      | 300000000 |      0 |
|  3 | Tom       |       100 |      0 |
+----+-----------+-----------+--------+

然后,接到上级命令,要把所有账户余额大于0的用户全部标识为富有,启动事务A完成这项任务,SQL如下:

update bank_balance set wealth = 1 where balance > 0;

SQL语句只是执行了,但是未提交。

紧接着,事务B插入了一条余额大于0的记录行(富有程度默认为贫穷),并且在事务A提交之前先提交了,SQL如下:

INSERT INTO `bank_balance` (`id`, `user_name`, `balance`) VALUES ('4', 'Eric', '500');

在这之后,如果事务A再发起相同条件的查询,会发现刚刚的更改对于某些数据未起作用(有些记录未被标识为富有),而且数据行比原来还多了!

这对于事务A而言,感觉出现了幻觉一样,这就是幻读现象

1.5 区别

读到这里,可能有些小伙伴就懵了,从脏读到幻读,感觉它们都一样的呀?其实,它们有实质性的区别:

1、脏读重在指一个事务读到了其他事务未提交的数据。

2、不可重复读主要在于一个事务中多次读到同一条数据,但前后读到的结果不一样,这是因为其他事务对数据进行修改并提交导致。

3、幻读则是因为被其他事务插入或者删除的数据影响,一个事务内同样条件的数据记录变多或者变少了。

二、事务隔离级别

前面已经讲完并行事务可能出现的问题,具体表象就是脏写,脏读,不可重复读,幻读。

针对这些问题,SQL定了一套标准,通过 隔离 来规避,且不同级别的隔离可以规避不同严重程度的事务问题,下面,我们一起看下SQL事务 隔离级别 都有哪些:

1. 读未提交(READ UNCOMMITTED),指一个事务还没提交,它做的修改就能被其他事务看到。

2. 读提交(READ COMMITTED),一个事务做的修改,只有提交之后,其他事务才能看到。

3. 可重复读(REPEATABLE READ),在整个事务过程中看到的数据,自始至终都是一致的。

4. 串行化(SERIALIZABLE),每个读写操作都会加锁,多个事务要访问同一条记录时,必须要进行排队,优先级低的事务必须等优先级高的事务完成以后才能进行。

从1到4,隔离级别依次变高,当然,性能也依次变差。那么这些隔离级别究竟都能防止哪些问题呢?来看一个表格:

只有串行化的隔离级别解决了全部这 3 个问题,其他的 3 个隔离级别都有一定的缺陷。

但,MySQL InnoDB引擎默认的隔离级别是可重复读(RR) 。

为什么MySQL没有使用串行化这个级别?是不是意味着我们日常使用MySQL会有可能存在幻读的问题?

非也! 隔离级别越高代价也是越高的 ,且性能也越差。从性能上来说,当然是隔离级别越低越好。

至于隔离级别是RR(可重复读)下的MySQL怎么避免幻读问题,InnoDB引擎有它自己的想法,以后单独抽一讲来说啦~

我们再来看一张图,理解不同隔离级别下读取到的数据是怎么样的:

有两个事务,事务A和事务B,同时操作(查询或者给Tom余额加100),事务B在事务A提交前更新了Tom的余额,并且事务B在事务A前提交。

1. 读未提交隔离级别 下,事务 B 修改余额后,事务 A 能够马上看见,即使事务B还未提交,所以事务 A 中余额 R1 查询的值是 200,余额 R2、R3 也是 200.

2. 读提交隔离级别 下,事务 B 修改余额后,只有事务B提交后事务A才能看见,所以事务A中余额R1查询在提交前,查的值是100,余额R2和余额R3都是在事务B提交后,查询得到的值都是200。

3. 可重复读隔离级别 下,事务A在提交前自始至终查到的值都必须一样,所以,余额R1、R2都是100,当事务A提交后再查询(其实是新事务)就能查到新的值,所以R3是200。

4. 串行化隔离级别 下,MySQL会给记录行以及记录行之间的'空行'加锁,如果是A事务先获得锁,那么B事务必须等到A事务提交以后才能更新数据。

比如上图,如果事务A查询Tom余额的SQL条件是'where user_name = "Tom"', user_name有唯一索引,所以只会给Tom账户这一行数据加共享锁 。

当B事务要去更新Tom的账户余额时,是获取不到锁的, 必须等待直至事务A完全提交 。

所以以上R1、R2查询得到的值都是100(这个时候事务B在排队等待),事务A提交以后, 事务B就可以更新值并提交了,R3是在事务B提交之后查询,所以是200。

好啦,今天就先讲到这里啦,或许大家一定还会有疑问:

比如

"以上这些隔离级别是如何实现的呢?"

"可重复读是怎么实现的?"

"读提交是怎么实现的?"

"MySQL默认的RR隔离级别是如何规避幻读的?"等等。

我都会一一讲完的,请关注我,等待我下一篇博文吧。

三、结语

我是tin,一个在努力让自己变得更优秀的普通工程师。自己阅历有限、学识浅薄,如有发现文章不妥之处,非常欢迎加我提出,我一定细心推敲并加以修改。

看到这里请安排个“三连”(分享、点赞、在看)再走吧,坚持创作不容易,你的正反馈是我坚持输出的最强动力,谢谢!

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

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

相关文章

MySQL 服务无法启动

问题场景: 启动mysql:net start mysql 临时解决办法: tasklist| findstr "mysql"taskkill/f /t /im mysqld.exemysqld --console重新打开一个cmd测试连接mysql 永久解决办法: 找到Mysql的根目录,删除dat…

云原生时代,如何通过极狐GitLab x KubeSphere 构建安全应用?

目录 DevSecOps 是什么?如何帮助我们打造云原生安全生态? 如何寻找云原生 DevSecOps 落地切入点? 第一层:K8s 安全 第二层:容器镜像安全 第三层:应用程序安全 这么多安全功能,如何去实现落…

RISCV Reader笔记_5 RV32A,RV32C

原子指令 RV32A 是 RISCV 支持原子操作的扩展。主要有两种实现方式:内存原子操作(AMO),加载保留/条件存储(load reserved / store conditional) AMO:一个处理器对内存的操作不会被打断&#xf…

数据库建表之外键关联

0前言 摘自某一段记事:   在实际的开发中,必然遇到“编辑操作”,而编辑操作,看似简单,实则其影响面甚广。本着设计的“贯穿性”和逻辑一致性,本文将按照,创建基础表的字段建议,创…

STM32 Proteus UCOSII系统水塔鱼缸水位控制系统-0052

STM32 Proteus UCOSII系统水塔鱼缸水位控制系统-0052 Proteus仿真小实验: STM32 Proteus UCOSII系统水塔鱼缸水位控制系统-0052 功能: 硬件组成:STM32F103R6单片机 LCD1602显示器多个按键(注水、排水)驱动电路电位…

HOT32-复制带随机指针的链表

leetcode原题链接:复制带随机指针的链表 题目描述 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xf…

企业如何判断是否选择CRM系统?

如今,以客户为中心的观点已经被广泛认可,想要建立以客户为中心的战略离不开CRM客户关系管理系统的应用,企业什么时候需要CRM?附CRM软件的选购指南。当企业出现这4点问题的时候证明是时候部署CRM了。 1.客户资料散乱 通常每个业务…

【结构型设计模式】桥接模式

一、写在前面 桥接模式(Bridge):桥接模式是一种结构型设计模式,其目的是将抽象部分和实现部分分离,允许它们可以独立地变化。该模式通过创建一个桥接类,连接抽象和实现,使得它们可以独立地进行…

【前端|CSS系列第3篇】CSS盒模型、浮动及定位

在前端开发中,CSS是一项重要的技术,用于控制网页的样式和布局。在本系列的第三篇文章中,我们将学习CSS的盒模型、浮动以及定位,这些概念和技术在页面布局中起着至关重要的作用。通过本文的学习,希望能够帮助大家更好地…

阿里云远程仓库环境安装

记录一些基本的命令: 一、apt-get,是一条linux命令,适用于deb包管理式的操作系统(例如Ubuntu系统),主要用于自动从互联网的软件仓库中搜索、安装、升级、卸载软件或操作系统。 // 常用命令: ap…

沐风老师3DMAX虚线对象插件Dashed使用方法详解

3DMAX虚线对象插件Dashed教程 Dashed虚线对象插件,用于沿拾取路径创建虚线(或实线)几何体对象 【主要特点】 -更多实用参数可以调节。 -沿着样条曲线测量距离值(如:笔划长度、间距、分段长度等)&#xff…

MySql的MVCC_存储引擎_历史_开发模式

概览 一. 多版本并发控制(MVCC)1.概述2.InnoDB的MVCC 二.MySql的存储引擎 一. 多版本并发控制(MVCC) 1.概述 可以认为MVCC是行级锁的一个变种,其在很多情况下避免了加锁操作,因此开销更低。 不同存储引擎的MVCC实现是不同的,但大部分实现了非阻塞的读…

Nginx(5)nginx的负载均衡

负载均衡 负载均衡的原理及处理流程负载均衡的作用 负载均衡常用的处理方式Nginx七层负载均衡Nginx七层负载均衡的指令Nginx七层负载均衡的实现流程 负载均衡状态负载均衡策略负载均衡案例案例一:对所有请求实现一般轮询规则的负载均衡案例二:对所有请求…

红色通信史(二):半部电台起家

上一期,我给大家介绍了“四一二”反革命政变后,我党在上海开通了第一部秘密电台的过程。 秘密电台的开通,标志着我党通信事业正式起步。然而,没过多久,顾顺章叛变,给上海党组织带来了极大的破坏。于是&…

事务

事务回顾MySQL事务Spring事务实现编程式事务实现:声明式事务 Transactional 注解作用范围及名称(value/transactionManager)隔离级别:isolation超时时间:timeout修改只读事务指定异常异常捕获情况 事务失效场景Transac…

高等数学II-知识点(1)——原函数的概念、不定积分、求原函数的两种常用方法 (凑微分法、第二换元法)、分部积分法、有理函数原函数求法、典型三角函数原函数求法

目录 原函数的概念 不定积分 定义 不定积分的基本积分公式 不定积分的运算法则 求原函数的两种常用方法 第一换元法(凑微分法) 第二换元法 分部积分法 有理函数原函数求法 典型三角函数原函数求法 原函数的概念 设在区间上有定义&#xff0c…

Python3 实例(一) | 菜鸟教程(十九)

目录 一、Python Hello World 实例 二、 Python 数字求和 (一)以下实例为通过用户输入两个数字,并计算两个数字之和: (二)两数字运算,求和我们使用了加号 ()运算符,除此外&#…

GB51309实施后对于消防应急照明和疏散指示系统在城市隧道应用中的影响

安科瑞 崔丽洁 【摘要】:应急照明和疏散指示系统被广泛运用于城市隧道、楼宇建筑、地下管廊等各个方面。当隧道这类特殊建筑内出现火灾或事故时,可靠的应急照明和疏散指示系统对于人员的安全逃生有着重要的作用。随着GB51309-2018《消防应急照明和疏散指…

java从入门到起飞(三)——三大结构(顺序结构、分支结构、循环结构)

目录 前提顺序结构分支结构if选择语句switch语句 循环结构for循环语句格式while循环语句格式do…while循环语句三种循环的区别三种循环的区别:for和while的区别:死循环格式: 前提 三大结构也成为流程控制语句,分为三大类&#xff…

flask+uwsgi+docker+nginx 云服务器部署测试平台

flaskuwsgidockernginx 云服务器部署测试平台 开发环境 本次主要是在腾讯云上进行部署,系统是CentOS 7.9 64位,主要使用的软件如下: Python 3.9.5 Pycharm Flask1.0.2 Mysql 5.7 nginx uwsgi 一 安装Nginx 1.更新yum 源 sudo rpm -ivh …