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

在「读未提交」和「读已提交」隔离级别下,都只会使用记录锁;而对于「可重复读」隔离级别来说,会使用记录锁、间隙锁和 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.mzph.cn/news/623957.shtml

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

相关文章

鸿蒙基础开发实战-(ArkTS)像素转换

像素单位转换API的使用 主要功能包括: 展示了不同像素单位的使用。展示了像素单位转换相关API的使用。 像素单位介绍页面 在像素单位介绍页面,介绍了系统像素单位的概念,并在页面中为Text组件的宽度属性设置不同的像素单位,fp…

Linux(Centos7)安装 jenkins(jdk11+jenkins2.375),并配置JDK,Maven,Git,GitLab

安装步骤 1. JDK11安装2. Maven安装3. git安装4. Jenkins2.375安装4.1 设置中文显示4.2 端口,用户权限修改4.3 插件下载4.4 全局工具配置4.4.1 Maven配置4.4.2 JDK配置4.4.3 Git配置 4.5 系统配置4.5.1 Gitee配置 4.6 构建测试 1. JDK11安装 #下载 yum -y install fontconfig …

进阶Docker2:数据卷和挂载目录

目录 准备 删除容器 创建并运行一个容器 数据卷(Volumes) 挂载数据卷 虚拟机端口映射 挂载目录(Bind mounts) 挂载目录 挂载文件 部署在线项目 docker 在容器中管理数据主要有两种方式: - 数据卷&#xff0…

图像处理-像素位置的一阶导数和二阶导数

图像处理-像素位置的一阶导数和二阶导数 空间卷积是一种图像处理中常用的技术,用于计算图像中每个像素位置的一阶导数和二阶导数。在这里将解释如何使用卷积操作来实现这些导数的计算。 一阶导数和二阶导数的性质: 一阶导数通常产生粗边缘&#xff1b…

4.2V锂电线性1.2A充电芯片WT4056

4.2V锂电线性1.2A充电芯片WT4056 WT4056是一款专为单节锂离子电池设计的恒流/恒压线性充电器。其简洁的外部电路设计使其非常适用于便携设备的供电,同时兼容USB电源和适配器电源。该充电器内部采用了防倒充电路,无需额外添加外部隔离二极管。通过热反馈…

Linux(适合开发人员参考)

Linux的概述 先了解Unix Unix是一个强大的多用户、多任务操作系统。于1969年在AT&T的贝尔实验室开发。UNIX的商标权由国际开放标准组织(The Open Group)所拥有。UNIX操作系统是商业版,需要收费,价格比Microsoft Windows正版…

Authing 入选中国信通院《 2023 高质量数字化转型产品及服务全景图》

近日,中国信通院“铸基计划”发布了《高质量数字化转型产品及服务全景图( 2023 )》。Authing 身份云成功入选 IT 维护与运营领域并获得证书。 “十四五”时期,我国数字经济转向深化应用、规范发展、普惠共享的新阶段,数字化转型已成为传统企业…

Notepad++编译运行C/C++程序

首先需要先下载一个C语言编译器-MinGW(免费的) 官网:http://www.mingw.org/(加载太慢) 我选择MinGW - Minimalist GNU for Windows download | SourceForge.net这个网址下载的 注意安装地址,后续配置环境…

什么是Java泛型?泛型在Java中应用场景

目录 一、什么是Java泛型 二、泛型类 三、泛型接口 四、泛型方法 一、什么是Java泛型 Java泛型是一种在编译时进行类型检查和类型安全的机制。它允许编写能够操作多种类型的代码,而不需要进行类型转换或使用Object类型。通过在定义类、接口或方法时使用泛型参数…

云原生微服务之分布式锁框架 Redisson

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列专栏目录 [Java项目…

数据仓库(3)-模型建设

本文从以下9个内容,介绍数据参考模型建设相关内容。 1、OLTP VS OLAP OLTP:全称OnLine Transaction Processing,中文名联机事务处理系统,主要是执行基本日常的事务处理,比如数据库记录的增删查改,例如mysql、oracle…

采样次数与频率的关系

采样次数(Sampling Points) 在给定时间内记录信号值的次数。 假设在1秒内对一个连续信号采样10次,这意味着每0.1秒记录一次信号值。 假设在1秒内对一个连续信号采样100次,这意味着每0.01秒记录一次信号值。 频率(Fre…

统一存储双控NAS同步备份应用方案

随着业务量的增加,企业必须找到一种有效的解决方案保护数据安全,防止不可预测的存储系统故障。传统的数据备份往往是专用的数据格式,不能保留完整的用户目录信息。因此,IT 人员必须在数据恢复后重新配置才可重新恢复业务。为了解决…

序章 初始篇—转生到vue世界!

Vue.js 是什么? Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项…

linux命令太多记不住吗?怎么办 ?于是推出了这样一套教程。

1.帮助命令 1.1 help命令 #语法格式: 命令 --help #作用: 查看某个命令的帮助信息 # 示例: # ls --help 查看ls命令的帮助信息# netstat --help 查看netstat命令的帮助信息1.2 man命令 #语法格式: man 命令 #作用: 查看某个命令的帮助手册 # 示例: …

递归(Recursion)

一、递归 递归:通过函数体来进行的循环 汇编:它没有所谓的循环嵌套这一说,你之前有一段指令写在什么地方,你不断的跳到之前的指令的地方去执行那条指令,这就是递归。 从前有个山山里有个庙庙里有个和尚讲故事返回1 …

智慧公厕!高科技手段提升城市品质与形象

近年来,随着科技的不断进步,智慧公厕正以其独特的功能和对公共厕所全方位的信息化和数字化,成为智慧城市建设中的重要一环,悄然崭露头角。如广州中期科技有限公司自主研发的智慧公厕管理系统,借助于厕位监测、环境监测…

数据结构期末复习(C语言版)

一、绪论 1.数据结构的术语 数据:所有能输入计算机并被计算机程序处理的符号的总称;数据元素:数据的基本单位;数据项:组成数据元素的、有独立含义的、不可分割的最小单位;数据对象:是性质相同…

数据结构学习 jz44 数字序列中某一位的数字

关键词:找规律 数学 题目:LCR 163. 找到第 k 位数字 虽然做出来了但是做了十万年,我是猪。主要还是找到准确的规律。 思路: //找规律 //0-9 占了10个位置 //10-99 占了90*2个位置 //100-999 占了900*3个位置 //1000-9999 占了90…

优思学院|质量管理五大工具和七大手法要点总结|2024

在现代企业管理中,质量管理是核心竞争力的重要组成部分。它不仅关系到产品的品质,更直接影响到企业的市场信誉和经济效益。本文将深入探讨质量管理中的五大工具及七大手法,这些工具和手法都贯穿了六西格玛DMAIC五步的方法论之中,是…