【MYSQL】MYSQL 的学习教程(十一)之 MySQL 不同隔离级别,都使用了哪些锁
聊聊不同隔离级别下,都会使用哪些锁?

1. MySQL 锁机制
对于 MySQL 来说,如果只支持串行访问的话,那么其效率会非常低。因此,为了提高数据库的运行效率,MySQL 需要支持并发访问。而在并发访问的情况下,会发生各种各样的问题,例如:脏读、不可重复读、幻读等问题。为了解决这些问题,就出现了事务隔离级别
本质上,事务隔离级别就是为了解决并发访问下的数据一致性问题的。不同的事务隔离级别,解决了不同程度的数据一致性
我们所说的全局锁、表锁、行级锁等等,其实都是事务隔离级别的具体实现。而 MVCC、意向锁,则是一些局部的性能优化
2. 事务隔离级别
MySQL 数据库有四大隔离级别:
- 读未提交(脏读):可以读取到其他事务还没提交的数据。 未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读
 - 读已提交(不可重复读):该隔离级别的事务能读取到已经提交事务的数据。 因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读
 - 可重复读(MySQL 的默认事务隔离级别:幻读):同一事务范围内读取到的数据是一致的。 但也会有新的问题,比如:此级别的事务正在执行时,另一个事务成功的插入了某条数据,两次查询结果记录条数不一样
 - 串行化:所有事务串行执行。 不用去竞争,一个个去执行,但是效率也是最低的 
- 当事务读取数据时,会获取共享锁,以确保数据的一致性。如果有其他事务已经持有排他锁,则读取操作需要等待排他锁释放
 - 当事务修改数据时,会获取排他锁,以防止其他事务读取或修改相同的数据。如果有其他事务已经持有共享锁或排他锁,则修改操作需要等待相关锁释放
 
 
3. MySQL 锁类型
在 MySQL 中有全局锁、表级锁、行级锁三种类型,其中比较关键的是表级锁、行级锁
MySQL 锁类型:
- 全局锁
 - 表级锁 
- 表锁:在 Innodb 存储存储引擎中,表锁也用得比较少
 - 元数据锁:基本上都是数据库自行操作
 - 意向锁
 
 - 行级锁 
- 记录锁:某个索引记录的锁
 - 间隙锁:两个索引记录之间的空隙锁
 - 临键锁:记录锁 + 间隙锁
 - 自增锁
 
 
在 Innodb 存储引擎中,我们可以通过下面的命令来查询锁的情况:
# 开启锁的日志
set global innodb_status_output_locks=on; 
# 查看innodb引擎的信息(包含锁的信息)
show engine innodb status\G;
 
查询结果一般如下图所示:

上面几种不同类型的锁,其各自的关键字为:
- 表级的意向排它锁(IX):lock mode IX。
 - 行级的插入意向锁(LOCK_INSERT_INTENTION): lock_mode X locks gap before rec insert intention
 - 行级的记录锁(LOCK_REC_NOT_GAP): lock_mode X locks rec but not gap
 - 行级的间隙锁(LOCK_GAP): lock_mode X locks gap before rec
 - 行级的 Next-key 锁(LOCK_ORNIDARY): lock_mode X
 
通过上面的命令,我们就可以知道不同的事务隔离级别使用了哪些锁了
4. 准备数据测试
CREATE TABLE `2022`.`price_test` (`id` BIGINT(64) NOT NULL AUTO_INCREMENT,`name` varchar(32) not null,`price` INTEGER(4) NULL,PRIMARY KEY (`id`));INSERT INTO price_test(name,price) values('apple', 10);
 
四种隔离级别:
READ UNCOMMITTED:读未提交READ COMMITTED:读已提交REPEATABLE READ:可重复读SERLIALIZABLE:序列化
5. 读未提交
打开两个命令行窗口,并且都修改事务隔离级别为「读未提交」
// 设置隔离级别
SET session TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
// 查看隔离级别
select @@transaction_isolation;
 
5.1 读写
- 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
 
begin;
select * from price_test where id = 1;
 
- 接着,事务 B 执行如下命令,修改 price 为 20
 
begin;
update price_test set price = 20 where id = 1;
 
- 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 读取到了事务 B 未提交的数据,这其实就是脏读了
 
select * from price_test where id = 1;
 

【结论】:在「读未提交」事务隔离级别下,读写是可以同时进行的,不会阻塞。
5.2 写写
事务 A 和 事务 B 同时对 id 为 1 的记录进行更新,看看是否能够更新成功
- 先用如下命令在事务 A(上边的窗口)执行,将 price 修改为 15,此时事务 A 还未提交。
 
begin;
update price_test set price = 15 where id = 1;
 
- 如下命令在事务 B(下边的窗口)执行,将 price 修改为 20,从图中可以看到,事务 B 阻塞卡住了
 
begin;
update price_test set price = 20 where id = 1;
 
【结论】:在「读未提交」事务隔离级别下,写写不可以同时进行的,会阻塞

通过查看锁信息可以看到,其是加上一个行级别的记录锁,如下图所示:

如果指定了非索引的列作为查询条件,是否会触发间隙锁呢?
插入一条数据:
INSERT INTO `2022`.`price_test` (`id`, `name`, `price`) VALUES (2, 'orange', 30);
 
-  
在事务 A 执行如下命令:
select * from price_test where price > 15 for update;,查询 price > 15 的记录: -  
接着,我们在事务 B 执行如下命令:
select * from price_test where price > 5 for update;,查询 price > 5 的记录。从如下结果可以看到,事务 B 阻塞住了: 

 3. 事务 A 查看锁的情况,如下图所示:

从上图可以看出,MySQL 只是加上了一个记录锁,并没有加间隙锁
5.3 总结
在「读未提交」隔离级别下,读写操作可以同时进行,但写写操作无法同时进行。与此同时,该隔离级别下只会使用行级别的记录锁,并不会用间隙锁
6. 读已提交
设置一下隔离级别为「读已提交」
SET session TRANSACTION ISOLATION LEVEL READ COMMITTED;
 
6.1 读写
- 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
 
begin;
select * from price_test where id = 1;
 
- 接着,事务 B 执行如下命令,修改 price 为 20
 
begin;
update price_test set price = 20 where id = 1;
 
- 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据,未产生脏读。
 
select * from price_test where id = 1;
 

6.2 写写
测试同时对 id 为 1 的数据进行更新:
- 事务 A 执行如下命令:
 
begin;
update price_test set price = 15 where id = 1;
 
- 接着事务 B 执行如下命令:
 
begin;
update price_test set price = 20 where id = 1;
 
- 事务 B 阻塞了。查看下锁信息,如下图所示
 

可以看到,其锁是一个行级别的记录锁,结果和「读未提交」的是一样的
继续看看范围的查询是否会触发间隙锁
- 事务 A 执行:
 
begin;
select * from price_test where price > 5 for update;
 
- 事务 B 执行:
 
begin;
select * from price_test where price > 15 for update;
 
- 事务 B 会阻塞,查看锁信息如下图所示
 

6.3 总结
在「读已提交」隔离级别下,只会使用行级别的记录锁,并不会用间隙锁。
6.4 读已提交隔离级别如何解决了【脏读】问题
脏读:是在并发事务中,一个事务可以读取到另一个未提交事务的数据
在“读已提交”隔离级别下,事务只能读取已经提交的数据,而不能读取未提交的数据。这意味着当一个事务正在进行修改时,其他事务无法读取到该事务所做的修改,直到该事务提交
为了实现"读已提交"隔离级别,数据库管理系统通常使用锁机制或多版本并发控制(MVCC)。锁机制可以确保一个事务在修改数据时对其他事务进行阻塞,以防止脏读。而MVCC则通过为每个事务创建不同的数据版本来实现隔离,并且只允许事务读取已提交的数据版本
7. 可重复读
我们设置一下隔离级别为「可重复读」
SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;
 
7.1 读写
- 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
 
begin;
select * from price_test where id = 1;
 
- 接着,事务 B 执行如下命令,修改 price 为 20
 
begin;
update price_test set price = 20 where id = 1;
 
- 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据,未产生脏读。
 
select * from price_test where id = 1;
 
7.2 写写
同时对 id 为 1 的数据进行更新,看看会发生什么
- 事务 A 执行如下命令:
 
begin;
update price_test set price = 15 where id = 1;
 
- 事务 B 执行如下命令
 
begin;
update price_test set price = 20 where id = 1;
 
- 事务 B 阻塞了。查看下锁信息,加上一个行级别的记录锁
 

继续看看范围的查询是否会触发间隙锁?
- 事务 A 执行:
 
begin;
select * from price_test where price > 5 for update;
 
- 事务 B 执行:
 
begin;
select * from price_test where price > 15 for update;
 
- 事务 B 会阻塞,查看锁信息如下图所示
 

可以看到,在这里就变成了 Next-Key 锁,就是记录锁和间隙锁结合体
7.3 总结
在「可重复读」隔离级别下,使用了记录锁、间隙锁、Next-Key 锁三种类型的锁
可重复读存在幻读的问题,但实际上在 MySQL 中,因为其使用了间隙锁,所以在「可重复读」隔离级别下,可用加锁解决幻读问题。因此,MySQL 将「可重复读」作为了其默认的隔离级别
8. 总结
对于任何隔离级别,表级别的表锁、元数据锁、意向锁都是会使用的,但对于行级别的锁则会有些许差别
- 在「读未提交」和「读已提交」隔离级别下,都只会使用记录锁,不会用间隙锁,当然也不会有 Next-Key 锁了
 - 对于「可重复读」隔离级别来说,会使用记录锁、间隙锁和 Next-Key 锁
 
相关文章:
【MYSQL】MYSQL 的学习教程(十一)之 MySQL 不同隔离级别,都使用了哪些锁
聊聊不同隔离级别下,都会使用哪些锁? 1. MySQL 锁机制 对于 MySQL 来说,如果只支持串行访问的话,那么其效率会非常低。因此,为了提高数据库的运行效率,MySQL 需要支持并发访问。而在并发访问的情况下&…...
LORA的基本原理
本文将介绍如下内容: 什么是Lora高效微调的基本原理LORA的实现方式LORA为何有效? 一、什么是LoRA LoRA 通常是指低秩分解(Low-Rank Decomposition)算法,是一种低资源微调大模型方法,论文如下: LoRA: Low…...
Vue2x的自定义指令和render函数使用自定义指令
在某些情况下,我们需要对底层DOM进行操作,而内置的指令不能满足需求,就需要自定义指令。一个自定义指令由一个包含类似组件的生命周期的钩子的对象来定义,钩子函数会接收到指令所绑定的元素作为参数。 定义指令 常用两种方式进行…...
Linux学习(2):文件目录指令
Linux学习(2):文件目录指令 1 文件目录指令1.1 pwd 用来显示当前目录的绝对路径的1.2 ls 显示当前目录的信息1.3 cd 切换到指定目录1.4 mkdir 创建目录1.5 rmdir 删除空目录1.6 touch 创建空文件1.7 cp 拷贝文件到指定目录1.8 rm 移除文件或目…...
Dockerfile的ENV
文章目录 环境总结测试测试1测试2测试3测试4测试5测试6 参考 环境 RHEL 9.3Docker Community 24.0.7 总结 如果懒得看测试的详细信息,可以直接看结果: 一条 ENV 指令可以定义多个环境变量。Dockerfile里可以包含多条 ENV 指令。环境变量的值不需要用…...
【普中开发板】基于51单片机的简易密码锁设计( proteus仿真+程序+设计报告+讲解视频)
基于51单片机的简易密码锁设计 1.主要功能:资料下载链接: 实物图:2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单 【普中】基于51单片机的简易密码锁设计 ( proteus仿真程序设计报告讲解视频) 仿真图proteus8.16(有低版本) 程…...
c语言之输出函数用法 putchar
putchar函数 putchar函数是c语言输出函数,但它只能输出单个字符,如果要输出字符串就不合适了。 应用举例 #include<stdio.h> int main() {putchar(a);putchar(4);putchar(\n);return 0: } 从上面代码可以看出,单字符必须用单引号’…...
高精度原边控制电路D3820,CC/CV精度±5%以内,可作为10W以下小功率、低待机功耗的电源替代,可兼容OB2520
高精度原边控制离线式PWM功率开关 特点 1、全电压范围CC/CV精度保持在5%以内 2、用原边控制,无需TL431和光耦 3、欠压锁定(UVLO)及自动重启 4、驱动BJT 5、内置前沿消隐(LEB) 6、逐周期限流模式 7、输出线压降…...
Python库学习(十四):ORM框架-SQLAlchemy
1.介绍 SQLAlchemy 是一个用于 Python 的 SQL 工具和对象关系映射(ORM)库。它允许开发者通过 Python 代码而不是 SQL查询语言来操作数据库。SQLAlchemy 提供了一种灵活且强大的方式来与关系型数据库交互,支持多种数据库后端,如 P…...
信息学奥赛一本通1014:与圆相关的计算
1014:与圆相关的计算 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 167892 通过数: 85008 【题目描述】 给出圆的半径,求圆的直径、周长和面积。输入圆的半径实数r,输出圆的直径、周长、面积,每个数保留小数点后4…...
Vscode——通过SSH连接服务器
1、打开vscode —— 点击左下角 2、选择SSH 3、点击后会自动安装三个插件 4、点击左下角——连接服务器 5、再次点击左下角——连接服务器 6、登录成功后打开终端即可操作 快捷键:ctrl ~ 7、查看编辑服务器文件目录 点击文件——打开文件夹 8、确定后再次输入登录密…...
UE5 通过接口实现角色描边效果
接口不能够被实例化,不能够在内部书写函数的逻辑和设置属性,只能够被继承使用。它能够让不同的类实现有相同的函数,继承接口的类必须实现接口的函数。 并且,我们可以在不同的类里面的函数实现也不同,比如A类描边是红色…...
电脑提示dll丢失怎么办,教你一招将dll修复
使用电脑时,你的电脑是否出现关于dll文件丢失或找不到的问题,出现这种问题又该如何解决呢,dll文件问题会导致软件无法打开,或者会导致系统崩溃。今天就来教大家如何快速解决dll文件修复。 一.如何修复dll修复 方法一:…...
MATLAB mat 文件
1.mat文件格式 MATLAB(Matrix Laboratory)使用 .mat 文件格式来存储和加载数据。MAT 文件是一种二进制文件格式,能够保存 MATLAB 中的各种数据类型,包括矩阵、向量、结构体、元胞数组等。 特定和用途: 二进制格式&a…...
Linux du和df命令
目录 一. df二. du 一. df ⏹用于显示系统级别,磁盘分区上的可用和已用空间的信息 -h:以人类可读的格式显示文件系统大小 ⏹每秒钟监视当前磁盘的使用情况 watch 用于周期性的执行特定的命令-n 1 表示每一秒刷新一次命令执行的结果df -h ./ 表示周期性…...
Adobe Photoshop 快捷键
PS快捷键 图层 选择图层 Ctrl T:可以对图层的大小和位置进行调整 填充图层 MAC: AltBackspace (前景) or CtrlBackspace (背景) WINDOWS: AltDelete (前景) or CtrlDelete (背景) 快速将图层填充为前景色或背景色 平面化图层(盖印图层)…...
缓存代理服务器
1 缓存代理 1.1 缓存代理的概述 web代理的作用 缓存网页对象,减少重复请求 存储一些之前被访问的或且可能将要备再次访问的静态网页资源对象,使用户可以直接从缓存代理服务器获取资源,从而减少上游原始服务器的负载压力,加快整…...
四道面试题
一.网络的七层模型 网络的七层模型,也被称为OSI七层协议模型,是一种用于理解和描述网络通信过程的概念模型。这个模型将网络通信过程划分为七个层次,从低到高分别是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层…...
BRC20 技术分析
文章目录 什么是 BRC20 ?brc20 白皮书。重点基于链上数据解析获取交易详情返回值如何将 16 进制转换为 字符串没有节点,如何获取数据?见证隔离如何解析出 BRC20 数据?最后如何快速搭建节点BRC20 Indexer...
【Unity】Timer计时器属性及使用
可以代替协程完成延时操作 可以不用Update进行计时 GitHub开源计时插件 网址:https://github.com/akbiggs/UnityTimer/tree/master 导入:URL:https://github.com/akbiggs/UnityTimer.git 基本功能: 创建计时器: Time…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
