【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 读写

  1. 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
begin;
select * from price_test where id = 1;
  1. 接着,事务 B 执行如下命令,修改 price 为 20
begin;
update price_test set price = 20 where id = 1;
  1. 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 读取到了事务 B 未提交的数据,这其实就是脏读
select * from price_test where id = 1;

在这里插入图片描述

【结论】:在「读未提交」事务隔离级别下,读写是可以同时进行的,不会阻塞。

5.2 写写

事务 A 和 事务 B 同时对 id 为 1 的记录进行更新,看看是否能够更新成功

  1. 先用如下命令在事务 A(上边的窗口)执行,将 price 修改为 15,此时事务 A 还未提交。
begin;
update price_test set price = 15 where id = 1;
  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);
  1. 在事务 A 执行如下命令:select * from price_test where price > 15 for update;,查询 price > 15 的记录:

  2. 接着,我们在事务 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 读写

  1. 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
begin;
select * from price_test where id = 1;
  1. 接着,事务 B 执行如下命令,修改 price 为 20
begin;
update price_test set price = 20 where id = 1;
  1. 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据,未产生脏读
select * from price_test where id = 1;

在这里插入图片描述

6.2 写写

测试同时对 id 为 1 的数据进行更新:

  1. 事务 A 执行如下命令:
begin;
update price_test set price = 15 where id = 1;
  1. 接着事务 B 执行如下命令:
begin;
update price_test set price = 20 where id = 1;
  1. 事务 B 阻塞了。查看下锁信息,如下图所示

在这里插入图片描述

可以看到,其锁是一个行级别的记录锁,结果和「读未提交」的是一样的

继续看看范围的查询是否会触发间隙锁

  1. 事务 A 执行:
begin;
select * from price_test where price > 5 for update;
  1. 事务 B 执行:
begin;
select * from price_test where price > 15 for update;
  1. 事务 B 会阻塞,查看锁信息如下图所示

在这里插入图片描述

6.3 总结

在「读已提交」隔离级别下,只会使用行级别的记录锁,并不会用间隙锁。

6.4 读已提交隔离级别如何解决了【脏读】问题

脏读:是在并发事务中,一个事务可以读取到另一个未提交事务的数据

在“读已提交”隔离级别下,事务只能读取已经提交的数据,而不能读取未提交的数据。这意味着当一个事务正在进行修改时,其他事务无法读取到该事务所做的修改,直到该事务提交

为了实现"读已提交"隔离级别,数据库管理系统通常使用锁机制或多版本并发控制(MVCC)。锁机制可以确保一个事务在修改数据时对其他事务进行阻塞,以防止脏读。而MVCC则通过为每个事务创建不同的数据版本来实现隔离,并且只允许事务读取已提交的数据版本

7. 可重复读

我们设置一下隔离级别为「可重复读」

SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;

7.1 读写

  1. 事务 A 执行如下命令,查询出 id 为 1 记录的 price 值,不提交事务
begin;
select * from price_test where id = 1;
  1. 接着,事务 B 执行如下命令,修改 price 为 20
begin;
update price_test set price = 20 where id = 1;
  1. 接着,事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据,未产生脏读
select * from price_test where id = 1;

7.2 写写

同时对 id 为 1 的数据进行更新,看看会发生什么

  1. 事务 A 执行如下命令:
begin;
update price_test set price = 15 where id = 1;
  1. 事务 B 执行如下命令
begin;
update price_test set price = 20 where id = 1;
  1. 事务 B 阻塞了。查看下锁信息,加上一个行级别的记录锁

在这里插入图片描述

继续看看范围的查询是否会触发间隙锁?

  1. 事务 A 执行:
begin;
select * from price_test where price > 5 for update;
  1. 事务 B 执行:
begin;
select * from price_test where price > 15 for update;
  1. 事务 B 会阻塞,查看锁信息如下图所示

在这里插入图片描述

可以看到,在这里就变成了 Next-Key 锁,就是记录锁和间隙锁结合体

7.3 总结

在「可重复读」隔离级别下,使用了记录锁、间隙锁、Next-Key 锁三种类型的锁

可重复读存在幻读的问题,但实际上在 MySQL 中,因为其使用了间隙锁,所以在「可重复读」隔离级别下,可用加锁解决幻读问题。因此,MySQL 将「可重复读」作为了其默认的隔离级别

8. 总结

对于任何隔离级别,表级别的表锁、元数据锁、意向锁都是会使用的,但对于行级别的锁则会有些许差别

  • 在「读未提交」和「读已提交」隔离级别下,都只会使用记录锁,不会用间隙锁,当然也不会有 Next-Key 锁了
  • 对于「可重复读」隔离级别来说,会使用记录锁、间隙锁和 Next-Key 锁

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

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

相关文章

【GO】如何用 Golang 的 os/exec 执行 pipe 替换文件

背景 主要记录一下怎么用 Golang 的 os/exec 去执行一个 cmd 的 pipeline,就是拿 cmdA 的输出作为 cmdB 的输入,这里记录了两种方法去替换文件里面的字符串。 pipe 那个逻辑在 demo1 里。 另外一种是直接读文件做替换,一不小心两个都放进来了…

[密码学][ecc]secp256k1

secp256k1 is the elliptic curve used in Bitcoin’s public key cryptography. It is defined by the equation y^2 x^3 7 and is based on the finite field mathematics. The “secp” in secp256k1 stands for “Standards for Efficient Cryptography” and “256” re…

CharRNN实现简单的文本生成

文本数字表示 统计文档中的字符,并且统计字符个数。这里是为了将文字转换为数字表示。 import numpy as np import re import torch class TextConverter(object):def __init__(self,text_path,max_vocab=5000):"""建立一个字符索引转换,主要还是为了生成一个…

【IPC通信--信号】

信号处理函数 • 信号发送函数 – kill(), sigqueue(), raise(), alarm(), setitimer(), pause() , abort() • 信号安装函数 – signal(), sigaction() • 信号集操作函数 – sigemptyset(), sigfillset(), sigaddset(), sigdelset(), sigismember() 信号发送函数—…

将yolov8的检测框从正框修改为旋转框需要做那些修改?

将yolov8项目修改为yolov8_obb项目需要修改模型结构(增加角度预测)、dataloader(使其支持dota格式数据)、修改TaskAlignedAssigner(使其支持带角度的bbox)、修改loss(新增对角度的训练)、修改metric(将hbb指标titile修改为obb)、修改绘图代码(使其能绘制旋转框)。 …

常用类型_日期..

1.Date java.util.Date是开发中常用的日期处理类(并非java.sql.Date类) 现在这么一个需求: 就是获取当前时区的时间 public class Main{public static void main(String[] args) {// d1和d2表示的时间都是一样的 所以推荐使用第一种写法 比较简洁Date d1 new Da…

MybatisPlus—快速入门

目录 1.使用MybatisPlus的基本步骤 1.1引入MybatisPlus的起步依赖 1.2 定义Mapper 2.MybatisPlus常用注解 2.1 TableName 2.2 TableId 2.3 TableField 2.4 小结 3. 常用配置 4. 总结 1.使用MybatisPlus的基本步骤 1.1引入MybatisPlus的起步依赖 MyBatisPlus官方提…

124基于matlab的禁忌搜索算法和蚁群优化算法优化TSP路径

基于matlab的禁忌搜索算法和蚁群优化算法优化TSP路径,动态输出路径规划过程及输出最小距离。数据可更换自己的,程序已调通,可直接运行。需要直接拍下,拍下后发邮箱。标价为程序价格,不包含售后。程序保证可直接运行。 …

【LeetCode】1211. 查询结果的质量和占比

Queries 表: ---------------------- | Column Name | Type | ---------------------- | query_name | varchar | | result | varchar | | position | int | | rating | int | ---------------------- 此表可能有重复的行。 此表包含了一…

【本科生通信原理】【实验报告】【北京航空航天大学】实验一:通信原理初步

一、实验目的: 熟悉 MATLAB开发环境、掌握 MATLAB基本运算操作;熟悉和了解 MATLAB图形绘制基本指令;熟悉使用 MATLAB分析信号频谱的过程;掌握加性白高斯噪声信道模型 二、实验内容: 三、实验程序: 1、 f…

爬取彼案壁纸

代码展现: 具体代码: import requests import re import os filename 壁纸\\ if not os.path.exists(filename): os.mkdir(filename) for i in range(2,11): url fhttp://www.netbian.com/index_{i}.htm headers {User-Agent: …

日常测试工作中哪些是必须知道的 SQL 语句?

SQL 简介 SQL(Structured Query Language,结构化查询语言)是一套用于管理关系数据库管理系统(RDBMS),基于 ANSI(American National Standards Institute 美国国家标准化组织)标准的计算机语言,比较重要的版本是 SQL92…

在Ubuntu22.04上离线部署Tailchat(一)

一:Tailchat介绍 Tailchat 是一款插件化易拓展的开源 IM 应用。可拓展架构赋予 Tailchat 无限可能性。前端微内核架构 后端微服务架构 使得 Tailchat 能够驾驭任何定制化/私有化的场景,是面向企业与私域用户打造,高度自由的群组管理与定制化…

大一,如何成为一名fpga工程师?

​ 1、数电(必须掌握的基础),然后进阶学模电(选学), 2、掌握HDL(HDLverilogVHDL)可以选择verilog或者VHDL,建议verilog就行。 3、掌握FPGA设计流程/原理(推…

KBDLT2.DLL文件丢失,软件或游戏无法启动,如何解决,试试这些方法,亲测有效

KBDLT2.DLL是Windows操作系统中的一个重要的动态链接库文件,它主要用于支持系统的键盘布局功能,尤其是与立陶宛语相关的键盘布局。 如果KBDLT2.DLL文件缺失或损坏,可能会导致一些问题。例如,当你试图使用立陶宛语键盘布局时&#…

Linux--vim操作

目录 前言 一、vim模式 二、底行模式的操作 三、命令模式的操作 四、替换模式 五、视图模式 六、vim的多文件编译 前言 本文主要讲解了vim的一些使用技巧。帮助我们轻松上手vim。 vim是一种多模式编辑器,通过vim打开文件并对文件进行编辑。 使用vim很简单…

MySQL四大引擎建库建表账号管理

目录 一. 数据库四大引擎 1.1 引擎查看 1.2 InnoDB引擎 1.3 MyISAM引擎 1.4 MEMORY引擎 1.5 Archive引擎 二. 数据库管理 2.1 元数据库 2.2 数据库的增删改查及使用 2.3 权限相关表 三. 数据表管理 3.1 三大范式 3.2 基本数据类型 优化原则 分类 四. 数据库账号…

Service Weaver:Google开源基于分布式应用程序开发的框架,重新定义微服务边界

大家好,我是萧楚河,公众号:golang面试经典讲解,感谢关注,一起学习一起成长。一、前言 今年6月,一群谷歌员工(由谷歌软件工程师Michael Whittaker领导)发表了一篇名为“Towards Mode…

wsl(ubuntu)创建用户

我们打卡ubuntu窗口,如果没有创建用户,那么默认是root用户 用户的增删改查 查 查询所有的用户列表 cat /etc/passwd | cut -d: -f1cat /etc/passwd: 这个命令用于显示 /etc/passwd 文件的内容。/etc/passwd 文件包含了系统上所有用户的基本信息。每一…

SpringBoot 中实现订单30分钟自动取消的策略

简介 在电商和其他涉及到在线支付的应用中,通常需要实现一个功能:如果用户在生成订单后的一定时间内未完成支付,系统将自动取消该订单。 本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案,并提供实例…