【MySQL 保姆级教学】事务的隔离级别(详细)--下(13)

news2024/12/26 20:49:13

事务的隔离级别

  • 1. 如何理解事务的隔离性
  • 2. 事务隔离级别的分类
  • 3. 查看和设置事务隔离级别
    • 3.1 全局和会话隔离级别
    • 3.2 查看和设置隔离级别
  • 4. 事务隔离级别的演示
    • 4.1 读未提交(Read Uncommitted)
    • 4.2 读已提交(Read Committed)
    • 4.3 可重复读(Repeatable Read)
      • 4.3.1 为什么要有可重复读?
      • 4.3.2 可重复读
      • 4.3.3 说明
    • 4.4 序列化(Serializable)
  • 5. 总结

1. 如何理解事务的隔离性

MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行。

一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性

但,毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。

比如,给同学1的任务是一次性把水池装满,给同学2的任务是一次性把水池的水放干:同学1在装水池的过程中而同学2放水池的水,结果他们俩个相互影响都完成不了任务。如果他们两个的工作隔离起来,先让同学1装水,水装满后同学2在进行放水,这样他们两个都可以完成任务。

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性

数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

2. 事务隔离级别的分类

  1. 读未提交(Read Uncommitted)
    定义:在读未提交隔离级别下,一个事务可以读取另一个事务尚未提交的数据。这是最低的隔离级别,允许脏读(Dirty Reads)。

    • 优点:提供最高的并发性能,因为事务之间几乎没有阻塞。
    • 缺点:可能会出现脏读,即读取到其他事务未提交的数据。可能会出现不可重复读(Non-repeatable Reads)和幻读(Phantom Reads)。
  2. 读已提交(Read Committed)
    定义:在读已提交隔离级别下,一个事务只能读取到另一个事务已经提交的数据。事务在每次读取数据时都会看到最新的已提交数据

    • 优点:避免了脏读。提供了较好的并发性能。
    • 缺点:可能会出现不可重复读,即在同一事务中多次读取同一数据时,可能会得到不同的结果。可能会出现幻读。
  3. 可重复读(Repeatable Read)
    定义:在可重复读隔离级别下,一个事务在执行期间多次读取同一数据时,结果始终相同,即使其他事务对这些数据进行了修改并提交。这是 MySQL 的默认隔离级别。

    • 优点:避免了脏读和不可重复读。提供了较高的数据一致性。
    • 缺点:可能会出现幻读,即在同一事务中多次执行相同的查询,可能会出现新的记录。
  4. 序列化(Serializable)
    定义:在序列化隔离级别下,事务被完全隔离,每个事务都按顺序执行,如同在单线程环境中一样。这是最高的隔离级别,确保了数据的一致性,但并发性能较差。

    • 优点:避免了脏读、不可重复读和幻读。提供了最高的数据一致性。
    • 缺点:并发性能较低,因为事务之间会有更多的阻塞和等待。

3. 查看和设置事务隔离级别

3.1 全局和会话隔离级别

  1. 全局隔离级别(Global Isolation Level)

    • 全局隔离级别为所有新会话的默认隔离级别
    • 一旦设置,所有新的会话将使用这个隔离级别,除非在会话中明确更改。
    • 对已经存在的会话没有影响
  2. 会话隔离级别(Session Isolation Level)

    • 会话隔离级别为当前会话的隔离级别。
    • 默认的使用是全局隔离级别
    • 修改后仅对当前会话有效,不影响其他会话

3.2 查看和设置隔离级别

全局隔离级别的设置:

SET GLOBAL TRANSACTION ISOLATION LEVEL isolation_level;

查询全局的隔离级别:

SELECT @@GLOBAL.TX_ISOLATION;

会话隔离级别的设置:

SET SESSION TRANSACTION ISOLATION LEVEL isolation_level;

查询会话的隔离级别:

SELECT @@SESSION.TX_ISOLATION;
SELECT @@TX_ISOLATION;

示例:
查询全局隔离级别和会话隔离级别:

# 查看全局隔离级别
select @@global.tx_isolation;

# 查看会话
select @@session.tx_isolation;

在这里插入图片描述
显然,全局隔离级别和会话隔离级别是一样的,因为当开启一个新的客户端时,会话隔离级别默认是全局的隔离级别

修改会话的隔离级别为 read uncommitted 读未提交,再次查询会话隔离级别

set session transaction isolation level read uncommitted;

在这里插入图片描述
显然,会话的隔离级别已经变为读未提交

修改全局的隔离级别为 read committed 读提交,然后查询全局和会话隔离级别

# 设置全局隔离级别
set global transaction isolation level read committed;

# 查询隔离级别
select @@global.tx_isolation;
select @@session.tx_isolation;

在这里插入图片描述
为什么全局隔离级别后,全局隔离级别和会话隔离接不一样呢?
答:会话隔离级别默认的是上次修改的(创建会话时默认全局隔离级别),修改全局隔离级别不能直接修改当前会话的隔离级别

退出MySQL,再次进入MySQL客户端,查看隔离级别

# 退出
quit

# 查询隔离级别
select @@global.tx_isolation;
select @@session.tx_isolation;

在这里插入图片描述
这时两者的隔离级别全是读提交

4. 事务隔离级别的演示

4.1 读未提交(Read Uncommitted)

字面的意思来理解,当一个客户端在事务中操作时并未提交事务,另一个客户端能读到该客户端操作的数据。

定义:在读未提交隔离级别下,一个事务可以读取另一个事务尚未提交的数据。这是最低的隔离级别,允许脏读(Dirty Reads)。

优点:提供最高的并发性能,因为事务之间几乎没有阻塞。

缺点:可能会出现脏读,即读取到其他事务未提交的数据。可能会出现不可重复读(Non-repeatable Reads)和幻读(Phantom Reads)。

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用

举例:
创建两个会话。左侧为客户端1,右侧为客户端2。

设置读未提交隔离级别:

set session transaction isolation level read uncommitted; 

在这里插入图片描述

在客户端1插入数据,客户端2查询数据。

	# 客户端1
	insert into students values(1, '李明', 18);
	# 创建保存点
	savepoint p1;
	
	# 客户端2
	select * from students;

在这里插入图片描述
显然,在客户端1执行命令后未使用commit提交,在客户端2就可以直接查询出操作结果。
一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读(dirty read)

在客户端1模拟崩溃;然后在客户端2查询数据

	# 客户端1
	`CRRL + D`
	
	# 客户端2
	select * from students;

在这里插入图片描述
很容易看出,当客户端1没有提交时系统崩溃后就会回滚到事务的开始,事务中所有的操作都会被撤销。

4.2 读已提交(Read Committed)

字面的意思来理解,当一个客户端在事务中操作时并提交事务后,另一个客户端才能读到该客户端操作的数据。

定义:在读已提交隔离级别下,一个事务只能读取到另一个事务已经提交的数据。事务在每次读取数据时都会看到最新的已提交数据

优点:避免了脏读。提供了较好的并发性能。

缺点:可能会出现不可重复读,即在同一事务中多次读取同一数据时,可能会得到不同的结果。可能会出现幻读。

举例:
创建两个会话。左侧为客户端1,右侧为客户端2。
设置读已提交隔离级别:

set session transaction isolation level read committed; 

在这里插入图片描述

在客户端1插入数据,客户端2查询数据。

	# 客户端1
	insert into students values(1, '李明', 18);
	
	# 客户端2
	select * from students;

在这里插入图片描述
可以发现,客户端1插入数据后在客户端2并不能查询到插入的数据。

这是为什么呢?
答:读已提交隔离级别,一个事务只能读取到另一个事务已经提交的数据,在事务未提交之前其他的客户端时不能读取到的。

在客户端1插入数据并提交,客户端2查询数据。

	# 客户端1
	insert into students values(2, '诸葛亮', 20);
	commit;
	
	# 客户端2
	select * from students;

在这里插入图片描述
显然,当客户端1提交事务后客户端2就能读到数据了。

4.3 可重复读(Repeatable Read)

4.3.1 为什么要有可重复读?

读已提交不是已经够完美了吗,为什么还要有可重复读呢?
答:读已提交只是看上去很方便,但是在实际的工作中会有很大的问题,主要的问题就在于在事务中能读到其他已经提交的事务。
比如,学校要给考试成绩好的学生发奖品,工作人员在筛选成绩的同时,另一工作人员发现第9名同学的成绩多算分了,正在减分。如图:
在这里插入图片描述
通过上图可知,小明的名字筛选出两次,那么生成的表中会有两个成绩不一样的名字。这肯定是不合适的。

4.3.2 可重复读

定义:在可重复读隔离级别下,一个事务在执行期间多次读取同一数据时,结果始终相同,即使其他事务对这些数据进行了修改并提交。这是 MySQL 的默认隔离级别。

优点:避免了脏读和不可重复读。提供了较高的数据一致性。

缺点:可能会出现幻读,即在同一事务中多次执行相同的查询,可能会出现新的记录。

举例:
创建两个会话。左侧为客户端1,右侧为客户端2。

设置可重复读隔离级别:

set session transaction isolation level repeatable read; 

在这里插入图片描述

在客户端1插入数据,客户端2查询数据。

	# 客户端1
	insert into students values(3, '李白', 20);
	
	# 客户端2
	select * from students;

在这里插入图片描述
可以发现,客户端1插入数据后在客户端2并不能查询到插入的数据。

在客户端1插入数据后提交事务,客户端2查询数据。

	# 客户端1
	insert into students values(4, '嫦娥, 18);
	commit;
	
	# 客户端2
	select * from students;

在这里插入图片描述
客户端1把事务提交后客户端2为什么还是不能查询到数据呢?
答:在可重复读隔离级别下,一个事务在执行期间多次读取同一数据时,结果始终相同,即使其他事务对这些数据进行了修改并提交。只用把自己的事务提交后,才能查询到其他已提交事务更改后的数据

提交客户端2的事务后再进行查询

# 客户端2
#提交事务
commit;

# 查询
select * from students;

在这里插入图片描述
显然,当客户端2提交事务后就可以查询到客户端已插入的数据。

4.3.3 说明

多次查看,发现终端A在对应事务中insert的数据,在终端B的事务周期中,也没有什么影响,也符合可重复的特点。

但是,一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据。

为什么?因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题,会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。

这种现象,叫做幻读(phantom read)。很明显,MySQL在RR级别的时候,是解决了幻读问题的

(解决的方式是用Next-Key锁(GAP+行锁)解决的。这块比较难,有兴趣同学了解一下)。

4.4 序列化(Serializable)

序列化也叫做串行化。
定义:在序列化隔离级别下,事务被完全隔离,每个事务都按顺序执行,如同在单线程环境中一样。这是最高的隔离级别,确保了数据的一致性,但并发性能较差。

优点:避免了脏读、不可重复读和幻读。提供了最高的数据一致性。

缺点:并发性能较低,因为事务之间会有更多的阻塞和等待。

举例:
创建两个会话。左侧为客户端1,右侧为客户端2。

  1. 场景1:两个客户端都查询数据,客户端2提交事务,然后客户端1提交事务。
    设置序列化隔离级别,开启事务

    set session transaction isolation level serializable; 
    

    在这里插入图片描述

    客户端1和客户端2都对表进行查询(此时两个事务都对表进行了加锁)

    # 客户端1
    select * from students;
    	
    # 客户端2
    select * from students;
    

    在这里插入图片描述

    客户端1进行插入表操作时发生锁等待
    在这里插入图片描述
    客户端1输入插入命令按回车键后,光标在命令的下面,说明该命令正在等待执行,这是为什么呢?

    答:在序列化隔离级别下,产生锁是为了确保数据的一致性;事务中的命令只要对表进行查询,就会锁住表,但是其他事务中的命令对此表也可以进行锁住;表只有被一个事务锁住时才能进行修改操作。

    此时的表被两个事务锁住了,客户端1想进行修改操作只有先让客户端2把事务提交(解开对表的锁)。

    客户端2对表解锁:

    # 客户端2
    commit;
    

    在这里插入图片描述

  2. 场景2:两个客户端都查询数据,然后都插入数据
    设置序列化隔离级别,开启事务

    set session transaction isolation level serializable; 
    

    在这里插入图片描述

    客户端1和客户端2都对表进行查询(此时两个事务都对表进行了加锁)

    # 客户端1
    select * from students;
    	
    # 客户端2
    select * from students;
    

    客户端1对表进行插入,客户端2对表进行插入

    # 客户端1
    insert into students values(6,'6',6);
    
    # 客户端2
    insert into students values(7,'7',7);
    

    在这里插入图片描述
    当客户端2对表进行插入的时候发生死锁,什么是死锁呢?
    答:两个事务试图同时访问同一个资源(比如插入同一条记录,就会发生死锁。MySQL会检测到这种情况,并返回错误信息,提示用户重启其中一个事务

    当客户端2发生死锁的时候就会被强制重启事务,此时读表的锁就只有客户端2了,客户端1对表的操作就可以进行了。

  3. 场景3:两个客户端都查询数据,客户端1插入数据(等待插入数据)
    设置序列化隔离级别,开启事务

    set session transaction isolation level serializable; 
    

    在这里插入图片描述

    客户端1和客户端2都对表进行查询(此时两个事务都对表进行了加锁)

    # 客户端1
    select * from students;
    	
    # 客户端2
    select * from students;
    

    客户端1对表进行插入,客户端2不进行任何操作

    # 客户端1
    insert into students values(6,'6',6);
    
    # 客户端2
    
    

    在这里插入图片描述
    执行步骤3后不在进行任何的操作,过几分钟后步骤4会自动弹出,修改表的操作尝试获取锁时超过了等待时间限制,导致事务无法继续执行

5. 总结

  • 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平
    衡点。
  • 不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了
  • 幻读的重点在于新增:同样的条件, 第1次和第2次读出来的记录数不一样
  • 说明:mysql 默认的隔离级别是可重复读,一般情况下不要修改
  • 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大。
隔离级别脏读不可重复读幻读加锁读
读未提交(read uncommit)YESYESYESNO
读已提交(read commit)NOYESYESNO
可重复读(repeatable)NONONONO
序列化(可串行化)(serializable)NONONOYES

一致性(Consistency)

  • 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务
    成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中
    断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一
    致)的状态。因此一致性是通过原子性来保证的。
  • 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑
    做支撑,也就是,一致性,是由用户决定的。
  • 而技术上,通过AID保证C

推荐阅读 :
如何实现事务的隔离性
Innodb中的事务隔离级别和锁的关系
MySQL间隙锁原理

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

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

相关文章

再见 阿里巴巴EasyExcel替代品EasyExcel-Plus即将诞生

最近阿里发布公告通知,停止对EasyExcel 更新和维护,EasyExcel 是一款知名的 Java Excel 工具库,由阿里巴巴开源,作者是玉霄,在 GitHub 上有 30k stars、7.5k forks。 据了解,EasyExcel作者玉霄)去年已经从…

Acrobat Pro DC 2023(pdf免费转化word)

所在位置 通过网盘分享的文件:Acrobat Pro DC 2023(64bit).tar 链接: https://pan.baidu.com/s/1_m8TT1rHTtp5YnU8F0QGXQ 提取码: 1234 --来自百度网盘超级会员v4的分享 安装流程 打开安装所在位置 进入安装程序 找到安装程序 进入后点击自定义安装,这里…

13载匠心独运,BI+AI启航新征程

13载匠心独运,BIAI启航新征程! 思迈特的13年,是在坚守中持续创新,在创新中不断追求卓越,是在挑战与机遇并行中开创全新篇章的历程。感谢每一位陪伴走过这段旅程的人。展望未来,思迈特将继续以初心为舵、以…

【大数据学习 | HBASE高级】storeFile文件的合并

Compaction 操作分成下面两种: Minor Compaction:是选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,对于删除、过期、多余版本的数据不进行清除。 Major Compaction:是指将所有的StoreFile合并成一个StoreFile&am…

git config是做什么的?

git config是做什么的? git config作用配置级别三种配置级别的介绍及使用,配置文件说明 使用说明git confi查看参数 默认/不使用这个参数 情况下 Git 使用哪个配置等级? 一些常见的行为查看配置信息设置配置信息删除配置信息 一些常用的配置信…

Warped Universe游戏即将在Sui上推出,为玩家提供多样化的游戏体验

Warped Games选择Sui作为其即将推出的创新多类型游戏Warped Universe的首选Web3技术。Warped Universe让玩家可以体验第三视角实时动作、回合制策略和基地建设等玩法。该游戏使用Unreal Engine 5开发,将借助Sui的技术使玩家能够拥有、交易和变现其游戏内资产。 War…

Autosar CP XCP规范导读

XCP 模块在汽车电子系统架构中起到重要作用,通过与多个模块的连接,实现了数据采集、校准、诊断等功能。它通过 RTE 进行控制,通过 PDUR 进行数据路由,通过通信硬件抽象层访问底层硬件,并与操作系统和其他相关模块协同工作,确保系统的稳定运行。 主要功能用途 通信协议支…

Scala学习记录,case class,迭代器

case class case class创建的对象的属性是不可改的 创建对象,可以不用写new 自动重写:toString, equals, hashCode, copy 自动重写方法:toString,equals,hashCode,copy 小习一下 1.case class 的定义语法是什么 基本形式:case …

B2B订货系统功能设计与代码开发(PHP + MySQL)

在B2B(Business to Business)电子商务中,企业之间的商品订购、交易和供应链管理是核心功能。一个高效的B2B订货系统可以帮助企业管理库存、订单、采购等业务流程。本文将介绍一个基于PHP与MySQL技术栈的B2B订货系统的功能设计与开发流程。 一…

前端CSS3 渐变详解

文章目录 CSS3 渐变详解一、引言二、CSS3 渐变基础1、线性渐变1.1、基本线性渐变1.2、改变渐变方向 2、径向渐变2.1、基本径向渐变2.2、设置径向渐变的中心 三、高级渐变技巧1、重复渐变1.1、重复线性渐变1.2、重复径向渐变 四、总结 CSS3 渐变详解 一、引言 在现代网页设计中…

2024-11-13 Unity Addressables2——寻址资源设置

文章目录 1 设置可寻址资源2 资源组窗口2.1 资源信息2.2 右键资源选项2.3 右键分组选项2.4 创建分组2.5 配置文件2.6 Tools 工具2.7 Play Mode Script2.7 构建打包 3 补充 1 设置可寻址资源 方法一:勾选 Inspector 窗口中的 “Addressable”。方法二:选…

课程讲解--哈夫曼树:原理、特性、应用与实践

前言 在这个信息如潮水般涌动的时代,我,一篇小小的文章,静静地躺在某个角落,怀揣着一份期待,一份对认可的渴望。 我可能没有华丽的辞藻堆砌成的璀璨外表,也没有跌宕起伏如传奇故事般的情节,但…

HP G10服务器ESXI6.7告警提示ramdisk tmp已满

物理服务器是HP G10 VCENTER内两台服务器报错提示ramdisk"tmp"已满,无法写入文件 登录ESXI命令行后发现两台主机的/tmp目录都没有空间了 定位到是ams-bbUsg.txt文件占用了大量的空间 1、关闭集群的DRS功能 2、迁移当前主机上面运行的所有虚拟机至其他主…

Mysql篇-Buffer Pool中的三大链表

为什么要有 Buffer Pool? 虽然说 MySQL 的数据是存储在磁盘里的,但是也不能每次都从磁盘里面读取数据,这样性能是极差的。 要想提升查询性能,那就加个缓存。所以,当数据从磁盘中取出后,缓存内存中&#xf…

万字长文解读深度学习——ViT、ViLT、DiT

文章目录 🌺深度学习面试八股汇总🌺ViT1. ViT的基本概念2. ViT的结构与工作流程1. 图像分块(Image Patch Tokenization)2. 位置编码(Positional Encoding)3. Transformer 编码器(Transformer En…

PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸

小编最近有一篇png图片要批量压缩,大小都在5MB之上,在网上找了半天要么就是有广告,要么就是有毒,要么就是功能复杂,整的我心烦意乱。 于是我自己用python写了一个纯净工具,只能压缩png图片,没任…

2.索引:MySQL 索引分类

MySQL中的索引是提高数据查询速度的重要工具,就像一本书的目录,可以帮助我们快速定位到所需的内容。选择适合的索引类型对数据库设计和性能优化至关重要。本文将详细介绍MySQL中常见的索引类型,并重点讲解聚集索引和二级索引的概念及应用。 1…

attention 注意力机制 学习笔记-GPT2

注意力机制 这可能是比较核心的地方了。 gpt2 是一个decoder-only模型,也就是仅仅使用decoder层而没有encoder层。 decoder层中使用了masked-attention 来进行注意力计算。在看代码之前,先了解attention-forward的相关背景知识。 在普通的self-atten…

Elasticsearch 8.16:适用于生产的混合对话搜索和创新的向量数据量化,其性能优于乘积量化 (PQ)

作者:来自 Elastic Ranjana Devaji, Dana Juratoni Elasticsearch 8.16 引入了 BBQ(Better Binary Quantization - 更好的二进制量化)—— 一种压缩向量化数据的创新方法,其性能优于传统方法,例如乘积量化 (Product Qu…

C语言 char 字符串 - C语言零基础入门教程

目录 一.char 字符串简介 二.字符和字符串区别 1.取值范围相同2.字符串由多个字符构成3.字符串和字符使用 printf 函数 三.char 字符串遍历四.猜你喜欢 零基础 C/C 学习路线推荐 : C/C 学习目录 >> C 语言基础入门 一.char 字符串简介 在C 语言中,除了前面介绍…