【MYSQL】MYSQL 的学习教程(十二)之 MySQL 啥时候用记录锁,啥时候用间隙锁

news2024/11/20 14:17:40

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

那么 MySQL 啥时候会用记录锁,啥时候会用间隙锁,啥时候又会用 Next-Key 锁呢?

在这里插入图片描述

1. 影响因素

影响其使用哪种行级锁的因素有:

  1. 索引类型(聚簇索引、唯一二级索引、普通二级索引)
  2. 匹配类型(精确匹配、范围匹配)
  3. 事务隔离级别
  4. 是否开启 Innodb_locks_unsafe_for_binlog 系统变量
  5. 记录是否被标记删除
  6. 具体的执行语句类型(SELECT、INSERT、DELETE、UPDATE)

测试数据:

CREATE TABLE `price_test`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `price` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `ind_price`(`price`) USING BTREE,
  INDEX `ind_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `price_test` VALUES (1, 'apple', 10);
INSERT INTO `price_test` VALUES (2, 'orange', 30);
INSERT INTO `price_test` VALUES (50, 'perl', 60);

2. 8 种情况

在看死锁日志的时候,我们一般先把这个变量 innodb_status_output_locks 打开哈,它是MySQL 5.6.16 引入的:

set global innodb_status_output_locks =on;

2.1 读可提交隔离级别

2.1.1 查询条件是主键

加一个记录锁

2.1.2 查询条件是唯一索引

加两个记录锁:主键索引上的一条记录;唯一索引上的一条记录

2.1.3 查询条件是普通索引

对应的所有满足 SQL 查询条件的记录,都会加上锁。同时,这些记录对应主键索引,也会上锁

2.1.4 查询条件列无索引

MySQL 会走聚簇索引进行全表扫描过滤。每条记录都会加上 X 锁。但是,为了效率考虑,MySQL 在这方面进行了改进,在扫描过程中,若记录不满足过滤条件,会进行解锁操作。同时优化违背了2PL原则

2.2 可重复读隔离级别

2.2.1 聚簇索引 + 精确匹配

  1. 事务 A 执行下面命令:
begin;
select * from price_test where id = 2 for update;
  1. 事务 B 执行下面命令:
begin;
update price_test set price = 25 where id = 2;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

可以看到,其是对 id 为 2 的索引加了一个记录锁

那如果聚簇索引的值找不到对应的记录呢,将会是一个什么样的结果呢?

  1. 事务 A 执行下面命令,其中 id 为 5 的记录是不存在的
begin;
select * from price_test where id = 5 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

加了一个间隙锁,该间隙锁是 (2, 50) 这个范围

  1. 事务 B 执行如下命令来测试下间隙锁的范围
begin;
// 执行下面任何一个命令,可以通过
update price_test set price = 25 where id = 2;
update price_test set price = 25 where id = 50;
// 执行下面任何一个命令,都将阻塞
insert into price_test(id,name,price) values(3,"test",25);
insert into price_test(id,name,price) values(5,"test",25);
insert into price_test(id,name,price) values(49,"test",25);

聚簇索引 + 精确匹配: 如果能够定位到唯一一条存在的记录,那么其会使用记录锁。如果该记录不存在,那么则会使用间隙锁

2.2.2 聚簇索引 + 范围匹配

  1. 事务 A 执行下面命令:
begin;
select * from price_test where id >= 2 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

事务 A 一共加了 3 个锁,其中 1 个记录锁,2 个 Next-Key 锁。其中 1 个记录锁是对 id 为 2 的索引加的锁,Next-Key 锁是对 (2, 50] 和 (50, 正无穷) 这两个区间加的锁

  1. 在事务 B 执行下面命令可以验证间隙锁的加锁区间:
begin;
// 执行下面任意一条语句,都会阻塞
update price_test set price = 25 where id = 2;
update price_test set price = 25 where id = 50;
insert into price_test(id,name,price) values(5,"test",25);
insert into price_test(id,name,price) values(60,"test",25);

如果范围匹配的值并不存在,那么会是什么情况呢?

  1. 事务 A 执行如下语句,其中 id 为 50 的记录是不存在的。
begin;
select * from price_test where id > 50 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

加了 1 个 Next-Key 锁,锁的范围应该是(50, + 无穷)

聚簇索引 + 范围匹配:存在匹配的值,会使用记录锁 + Next-Key 锁;不存在匹配的值,只会使用 Next-Key 锁

2.2.3 唯一二级索引 + 精确匹配

  1. 事务 A 执行下面命令
begin;
select * from price_test where price = 10 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

加的行级锁是 2 个记录锁,应该是 price = 10 这条索引记录的锁

  1. 此时,如果在事务 B 执行下面命令:
begin;
// 执行下面任意一条语句,都会阻塞
update price_test set name = 'test-name' where price = 10;

那如果唯一二级索引的值找不到对应的记录呢,将会是一个什么样的结果呢?

  1. 事务 A 执行下面命令,其中 price 为 11 的记录是不存在的
begin;
select * from price_test where price = 11 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

加了一个间隙锁,该间隙锁是 (10, 30) 这个范围

唯一二级索引 + 精确匹配:唯一二级索引与聚簇索引非常类似,如果能够定位到唯一一条存在的记录,那么其会使用记录锁。如果该记录不存在,那么则会使用间隙锁

2.2.4 唯一二级索引 + 范围匹配

  1. 事务 A 执行下面命令:
begin;
select * from price_test where price >= 30 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

一共加了 5 个行锁,2 个记录锁(price 为 30、60 的记录),3 个 Next-Key 锁, 。3 个 Next-Key 锁则是 (10, 30]、(30,60]、(60, 正无穷)三个范围

  1. 在事务 B 执行下面命令,每条 SQL 都会阻塞住:
begin;
// 执行下面任意一条语句,都会阻塞
update price_test set name = 'price30' where price = 30;
update price_test set name = 'price60' where price = 60;
insert into price_test(id,name,price) values(5,"test", 20);
insert into price_test(id,name,price) values(5,"test", 40);
insert into price_test(id,name,price) values(5,"test", 70);

如果范围匹配的值并不存在,那么会是什么情况呢?

  1. 事务 A 执行下面命令:
begin;
select * from price_test where price >= 70 for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

加了一个 Next-key 锁 (60, 正无穷)

聚簇索引 + 范围匹配:存在匹配的值,会使用记录锁 + Next-Key 锁;不存在匹配的值,只会使用 Next-Key 锁

2.2.5 普通二级索引 + 精确匹配

  1. 事务 A 执行下面命令:
begin;
select * from price_test where name = 'apple' for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

一个记录锁 (name = ‘apple’)、间隙锁(范围: (负无穷,orange))、Next-key 锁(二级索引的记录锁 + 间隙锁)

  1. 事务 B 执行如下命令验证一下
begin;
// 执行下面任意一条语句,都会阻塞
update price_test set name = 'apple-new' where name = 'apple';
insert into price_test(id,name,price) values(5,"aa", 20);
insert into price_test(id,name,price) values(5,"ha", 20);
// 执行下面的语句正常执行
update price_test set name = 'orange-new' where name = 'orange';
insert into price_test(id,name,price) values(5,"orb", 20);

之所以二级索引的精确匹配会有间隙锁,是因为二级索引可能匹配到多个。因此当匹配到一个的时候,会继续往后匹配,直到匹配到一个不符合的记录,随后就会以该不符合的记录(这里是 orange)作为值做一个间隙锁

普通二级索引 + 精确匹配:若匹配到记录,则使用记录锁 + 间隙锁 + Next-Key 锁;否则,只使用间隙锁

2.2.6 普通二级索引 + 范围匹配

  1. 事务 A 执行下面命令:
begin;
select * from price_test where name >= 'orange' for update;
  1. 执行 show engine innodb status\G; 查看锁信息如下图所示

在这里插入图片描述

一共有 2 个记录锁,3 个 Next-Key 锁。其中 2 个记录锁应该是 orange 和 perl 两个记录,3 个 Next-Key 锁,应该是 (apple, orange]、[orange, perl)、[perl, 正无穷)

  1. 事务 B 执行如下命令验证一下:
begin;
// 执行下面任意一条语句,都会阻塞
// 验证记录锁
update price_test set price = 1 where name = 'orange';
update price_test set price = 1 where name = 'perl';
// 验证间隙锁
insert into price_test(id,name,price) values(5,"ba", 20);
insert into price_test(id,name,price) values(5,"orb", 20);
insert into price_test(id,name,price) values(5,"pes", 20);
// 执行下面的语句正常执行
update price_test set price = 1 where name = 'apple';
insert into price_test(id,name,price) values(5,"aa", 20);

普通二级索引 + 范围匹配:存在匹配的值,使用记录锁 + Next-Key 锁;若不存在,则使用 Next-Key 锁

2.2.7 无索引

如果查询条件列没有索引,主键索引的所有记录,都将加上 X 锁,每条记录间也都加上间隙 Gap 锁。大家可以想象一下,任何加锁并发的 SQL,都是不能执行的,全表都是锁死的状态。如果表的数据量大,那效率就更低

在这里插入图片描述

在这种情况下,MySQL 做了一些优化,即 semi-consistent read,对于不满足条件的记录,MySQL 提前释放锁,同时 Gap 锁也会释放。而 semi-consistent read 是如何触发的呢:要么在 Read Committed 隔离级别下;要么在 Repeatable Read 隔离级别下,设置了 innodb_locks_unsafe_for_binlog 参数。但是 semi-consistent read 本身也会带来其他的问题,不建议使用。

2.3 Serializable 串行化

在 Serializable 串行化的隔离级别下,对于写的语句,比如 update account set balance= balance-10 where name=‘Jay’;,跟RC和RR隔离级别是一样的。不一样的地方是,在查询语句,如 select balance from account where name = ‘Jay’;,在 RC 和 RR 是不会加锁的,但是在 Serializable 串行化的隔离级别,即会加锁

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

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

相关文章

美客多本土店与跨境店有何区别?本土店如何入驻运营?

美客多被誉为“拉美亚马逊”,作为拉美地区最大的跨境电商平台,吸引了不少跨境电商卖家入驻。但在入驻过程中也会遇到一个问题,本土店与跨境店分别是什么?有何区别?应该选择本土店还是跨境店入驻呢?下面为你…

使用YOLOv5训练自己的数据集 --- 老鼠识别

方式一:YOLOv5开源地址:https://github.com/ultralytics/yolov5/blob/master/README.zh-CN.md 方式二:YOLOv5源码:https://pan.baidu.com/s/12khk-Wkc5_J5ho4oZ7_FhA?pwdxtru 安装环境依赖包: 项目目录地址栏中输入…

MobaXterm游戏讲解

前言 没想到吧,这里还有游戏,以下是玩法 玩法 注 点击Type可以自由更改地图大小 1.Netwalk 这个游戏是用鼠标点击每一个格子,进行旋转方向,使得所有方块连接接来,全部变成亮蓝色 2.Mines 这个就是扫雷了&#xff…

算法训练营Day42(背包问题)

基础 非竞赛只需要搞懂0-1背包和完全背包 0-1背包基础 0-1背包是完全背包和多重背包的基础 n个物品,每个物品一个,每个物品有自己的重量和价值,,一个背包能装m物品,问最多装多少物品。 暴力解法,n个物品…

循环中的continue和break | python

1 continue continue关键字用于:中断本次循环,直接进入下一次循环 continue可以用于:for循环和while循环,效果一致 上侧代码: 在循环内,遇到continue就结束当次循环,进行下一次所以,语句2是不会执行的。 1.1 应用场…

网点分散难管理?组网是物流企业的正解!

物流企业服务网点分散、难以管理是企业面临的一个问题,而组网是解决这一问题的正解。通过建立统一的网络,物流企业可以实现更好的资源管理和信息流动,从而提高运营效率和服务水平,实现企业的可持续发展。 随着物流业务的不断拓展…

pycharm导入etree报Cannot find reference ‘etree‘ in ‘__init__.py‘ more... (Ctrl+F1)

问题 发现 from lxml import etree的时候,etree报错了。提示Cannot find reference etree in __init__.py more... (CtrlF1)。 解决办法 后面发现是pycharm自己的BUG,所以写了新的写法

黑马苍穹外卖学习Day2

文章目录 员工管理模块实现新增员工需求设计分析代码开发功能测试代码完善 员工分页查询需求分析与设计代码开发功能测试代码完善 启用禁用员工账号需求分析和设计代码开发功能测试 编辑员工需求分析代码开发 导入分类模块功能代码需求分析设计 员工管理模块实现 新增员工 需…

小程序基础学习(组件化)

(一)创建 找到components文件夹下面创建新的文件夹 然后再文件夹内创建component格式的文件 创建后这样 我创建的是my-info的文件夹以及my-info的components文件,跟着普通的页面一样 (二) 注册组件 找到你需要使用组…

刚开始学习 c++ 要注意哪些方面?

刚开始学习 c 要注意哪些方面? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&…

API获取商品详情电商补单及价格监控调用api

很多电商系统,如返利系统、ERP、OMS软件等,需要通过商品API接口获取商品详情信息,来满足业务场景需要。具体包括:商品的标题、价格、SKU、主图、评价等维度信息 获取key和密钥 返回数据: {"item": {"…

MacOS安装Miniforge、Tensorflow、Jupyter Lab等(2024年最新)

大家好,我是邵奈一,一个不务正业的程序猿、正儿八经的斜杠青年。 1、世人称我为:被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员… 2、这几年,我整理了很多IT技术相关的教程给大家&#xff0…

查看Linux磁盘空间

(1)、该命令会列出当前系统所有挂载的文件系统以及它们的使用情况,包括总容量、已用空间、可用空间、使用百分比等信息 df -h如果查看某一个文件夹的,可以 df -h folderName (2)、计算指定目录下所有文件和子目录所占用的磁盘空间大小,并以人类可读的格…

创建型模式 | 工厂模式

文章目录 一、简单工厂1.1、原理1.2、核心角色1.3、UML类图1.4、代码实现1.5、总结 二、工厂模式2.1、原理2.2、关键角色2.3、代码实现2.4、总结 三、抽象工厂模式3.1、原理3.2、关键角色3.3、UML类图3.4、工厂模式与抽象工厂模式的区别 前言 工厂模式是最常用的设计模式之一&a…

ROS---激光雷达的使用

ROS—激光雷达的使用 激光雷达是现今机器人尤其是无人车领域及最重要、最关键也是最常见的传感器之一,是机器人感知外界的一种重要手段。本文将介绍在ROS下使用激光雷达传感器,我们选用的激光雷达型号为思岚A1。 使用流程如下: 硬件准备;软…

C++——简介、Hello World、变量常量、数据类型

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…

idea编译报错(Maven项目)

idea编译报错 找不到符号 第一步:开启注解处理器 第二步:清理MVN,package并重新编译 第三步:重新导入项目:

本地开发环境请求服务器接口跨域的问题(vue的问题)

上面的这个报错大家都不会陌生,报错是说没有访问权限(跨域问题)。本地开发项目请求服务器接口的时候,因为客户端的同源策略,导致了跨域的问题。下面先演示一个没有配置允许本地跨域的的情况: 可以看到&…

【亲测有效】Win11 卸载MySQL5.7以及安装MySQL8.0.35

目录 一、卸载原来本地的mysql5.7 1.mysql服务部分 1.1停止mysql服务 1.2删除mysql服务 2.卸载 MySQL程序 3.残余文件的清理 3.1删除mysql安装的目录 3.2删除mysql数据存放的目录 3.3删除mysql自定义目录 4.清理注册表 5.删除环境变量配置 二、安装mysql8.0.35 1.…

Explain详解与索引最佳实践

Mysql安装文档参考:https://blog.csdn.net/yougoule/article/details/56680952 Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈 在 select 语句之前增加 explain 关键字,MySQL 会在查询…