68 mysql 的 临键锁

前言

我们这里来说的就是 我们在 mysql 这边常见的 一种锁, 行临键锁

虽然 在平时我们用到的不是很多, 我们这里 主要是 讲一下 它的主要的触发的场景

行临键锁 等价于 行锁 + 间隙锁, 行间隙锁是一个 左开右开的区间, 行临键锁 是一个左开右闭的区间

但是 它 和 行锁的差异仅仅在于 mode 的标记, 行锁这边是 LOCK_NOT_GAP + LOCK_X, 行临键锁 这边是 LOCK_ORDINARY + LOCK_X

 

我们这里测试表结构如下 

CREATE TABLE `tz_test_04` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `field1` varchar(128) DEFAULT NULL,
  `field2` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `field_1_2` (`field1`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8

 

测试数据如下, 之所以 留下一些区间 是为了产生 “间隙”

f5dc0cbf2d3eb40e06a0ff07bbba2ff3.png

 

 

添加临键锁

这里的整体流程, 以及相关上下文 基本上都和 添加 行锁类似

仅仅是在不同的语境中, 一部分语境使用的是 行锁, 一部分语境使用的 行临键锁

我们来看一下 两者的选择的区别

首先是默认值, 如果是 空间索引 或者 已提交读隔离级别以下 或者 根据查询条件唯一定位记录 等等情况默认值是 行锁, 否则是临键锁 

另外就是一个特殊的情况下使用使用行锁, 比如在 ”id >= 100” 的条件下, 匹配到了 “id = 100” 的记录, 则只在该记录上面添加行锁 

是使用行锁 还是 临键锁 的关键就是 查询结果是否唯一

1c1afaed1b26e9bbaeadfd8ccaa6b9bc.png

 

 

基于 主键/唯一索引 的查询

1. select * from tz_test_04 where id = 5 for update;

根据主键查询的一条存在的记录 

可以看到添加的是 行排他锁, 因为这个查询从理论上来说是可以最多定位到一条记录 

cbfc0dbe7acd29b5865ea93cad4fdc88.png

 

 

2. select * from tz_test_04 where id = 7 for update;

根据主键查询的一条不存在的记录 

可以看到添加的是 行间隙排他锁 

668043363f1a2434be440026dc499f0d.png

 

 

3. select * from tz_test_04 where id <> 5 for update;

不等于查询是转化为了 两个区间查询, 这两个 我们在 >, < 的地方查看具体的加锁处理 

select * from tz_test_04 where id < 5 for update;

select * from tz_test_04 where id > 5 for update;

 

第一个查询区间 

3c802db678f38c883bb89675ac0c07c5.png

 

第二个查询区间 

98e235abf5dd4b0cdc1f03a1d95b9054.png

 

 

4.select * from tz_test_04 where id > 5 for update;
5.select * from tz_test_04 where id >= 5 for update;

因为是非唯一查询, 在扫描过的记录上面增加 临键锁

  • sql, 会扫描 id=10, supremum 两条记录, 都加上临键锁, 锁定的区间是 (5, 正无穷]
  • sql, 会扫描 id=5, id=10, supremum 三条记录, id=5的记录增加行锁, 另外两条都加上临键锁, 锁定的区间是 [5, 正无穷]

dc9a9af061fc1697ef9a5a00f82c024f.png

 

select * from tz_test_04 where id >= 5 for update; 的 sql, 在 id=5 的记录上面增加行锁的处理如下 

从 rec + 0x11, 可以判断当前记录是 id=5, 然后从 mode, gap_mode 可以判断出当前是在该记录上面增加的 行排他锁

4e443f954543e35802833046ece43ab6.png

 

对于如下五条 sql, 第一条 都可以正常执行

第二条, 对于限定 id>5 的 sql, 这条 sql 会正常执行, 报错 主键重复, 对于限定 id>=5 的 sql, 这条 sql 会阻塞

对于 后面三条 sql, 都会阻塞

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (4, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (5, 'field8', '8');

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (10, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field8', '8');

 

 

6.select * from tz_test_04 where id < 5 for update;
7.select * from tz_test_04 where id <= 5 for update;

这个和上面同理, 我们这里直接说结论了 

因为是非唯一查询, 在扫描过的记录上面增加 临键锁

第一条 sql, 会扫描 id=1, id=5 两条记录, 都加上临键锁, 锁定的区间是 (负无穷, 5]

第二条 sql, 会扫描 id=1, id=5, id=10 三条记录, 都加上临键锁, 锁定的区间是 (负无穷, 10]

 

对于如下五条 sql, 第一条, 第二条 都会阻塞

第三条, 第四条 对于 “id<5” 可以正常执行, 对于 “id<=5” 会阻塞 

对于第五条 sql, 都可以正常执行 

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (4, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (5, 'field8', '8');

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (10, 'field8', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field8', '8');

 

 

基于 普通索引 的查询

这里来看一下 以上的情况对于 普通索引 上面查询的执行情况

 

1. select * from tz_test_04 where field1 = 'field5' for update;

根据索引查询的存在的记录 

这个会增加 三个锁, 会在 field1=’field5’ 上面增加一个 临键锁, 在具体的数据行记录上面增加行排他锁, 在下一个索引记录上面增加一个间隙锁

所以 在 field1 索引上面, 锁定的是 (field1, field9), 在 id=5 数据行上面加的 行排他锁

但是因为 我们这里的普通索引是可能重复的, 因此 具体索引记录是添加在第一个 field9 之前, 还是最后一个 field9 之后, 这个取决于数据库的实现 

但是实际锁定的区间 还取决于带插入的索引记录在整体记录的排序

 

索引 field1=’field5’ 上面增加 临键锁

51caf89780fed8cdeb3871c3a5ab176e.png

 

id=5 的数据记录上面增加行锁 

1ae1316f757af719f1bda8768b4a65a8.png

 

索引 field1=’field5’ 上面增加 间隙锁, 但是 这里实际的功能是等价于一个 临键锁

00ac89c5bf04b4010caf11c89231dfda.png

 

对于如下四条 sql, 第一条, 第二条 都会阻塞

第三条 会阻塞, 第四条不会阻塞 

然后 第五条 不会阻塞

和 第四条的差异在于, 数据库中 索引记录的排序是 (field1, id), 我们锁定的记录是 (field9, 10), 第三条 sql 插入的记录是 (field9, 8) 是排在锁定记录之前的, 还在锁定的逻辑区间, 因此算冲突 

插入的记录是 (field9, 15) 是排在锁定记录之后的, 不在锁定的逻辑区间, 可以正常处理业务

因此 确定索引锁定的区间是 索引+聚簇索引 来确定的

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field1', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (9, 'fielda', '8');

 

 

2. select * from tz_test_04 where field1 = 'field7' for update;

根据索引查询的不存在的记录 

可以看到添加的是 行间隙排他锁, 这里的 gap_mode 为 LOCK_GAP

逻辑上锁定的区间是 索引字段 field1 的区间 (field5, field9), 但是实际锁定的区间 还取决于带插入的索引记录在整体记录的排序

04de465c1c574b5ac03abd6be5f2558e.png

 

对于如下五条 sql, 第一条, 第二条 不会阻塞

第三条, 第四条 会阻塞

第五条, 第六条 不会阻塞 

具体的原因就和上面一致, 确定索引锁定的区间是 索引+聚簇索引 来确定的

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field1', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (2, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (9, 'fielda', '8');

 

 

3. select * from tz_test_04 where field1 <> 'field5' for update;

不等于查询是转化为了 全表查询 或者 两个区间查询, 这两个 我们在 >, < 的地方查看具体的加锁处理 

如果是全表查询 则是在扫描的记录上面增加 行临键锁

我们这里的实际情况是 进行了全表的扫描, mysql 认为这样开销较小一些 

 

 

4. select * from tz_test_04 where field1 > 'field5' for update;
5. select * from tz_test_04 where field1 >= 'field5' for update;

第一条 sql 会扫描 field1='field9', supremum 两条记录, 都加上临键锁, 锁定的区间是 ((field5,5), 正无穷], 并会在 id=10 的数据记录上面增加 行排他锁

第二条 sql 会扫描 field1='field5', field1='field9', supremum 三条记录, 都加上临键锁, 锁定的区间是 ((field1,1), 正无穷], 并会在 id=5, id=10 的数据记录上面增加 行排他锁

 

对于如下 六条 sql 

对于 field1>’field5’ 前面两条可以正常执行, 后面四条会阻塞 

对于 field1>=’field5’ 这里的六条都会阻塞 

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field1', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (2, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (9, 'fielda', '8');

 

 

6. select * from tz_test_04 where field1 < 'field5' for update;
7. select * from tz_test_04 where field1 <= 'field5' for update;

第一条 sql 会扫描 field1='field1', field1='field5' 两条记录, 都加上临键锁, 锁定的区间是 (负无穷, (field5,5)], 并会在 id=1 的数据记录上面增加 行排他锁

第二条 sql 会扫描 field1='field1', field1='field5', field1='field9' 三条记录, 都加上临键锁, 锁定的区间是 (负无穷, (field9,9)], 并会在 id=1, id=5 的数据记录上面增加 行排他锁

 

对于如下 六条 sql 

对于 field1<’field5’ 前面两条会阻塞, 后面四条会正常执行 

对于 field1<=’field5’ 前面四条会阻塞, 后面两条正常执行

INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field1', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (2, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field5', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (8, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (15, 'field9', '8');
INSERT INTO `test_02`.`tz_test_04`(`id`, `field1`, `field2`) VALUES (9, 'fielda', '8');

 

 

临键锁的使用 以及 释放

这个参见 行锁, 间隙锁 相关 

这里不再 赘述

 

 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(数据结构与算法)如何提高学习算法的效率?面试算法重点有哪些?面试需要哪些能力?

面试官眼中的求职者 通过对你算法的考察&#xff01;&#xff01;&#xff01;&#xff01; 缩进太多&#xff01;&#xff01;一般不要超过三层&#xff01;&#xff01;&#xff01;缩进越少&#xff0c;bug越少&#xff1b;逻辑比较复杂&#xff0c;把这些包装成为函数&…

设计模式-适配器模式-注册器模式

设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台&#xff0c;需要适配或接入不同的数据源&#xff0c;可能提供的方法参数和平台调用的方法参数不一致&#xff0c;可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…

SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD

目录 一、OFD 简介1.1 什么是 OFD&#xff1f;1.2 什么是 版式文档&#xff1f;1.3 为什么要用 OFD 而不是PDF&#xff1f; 二、ofdrw 简介2.1 定义2.2 Maven 依赖2.3 ofdrw 的 13 个模块 三、PDF/文本/图片 转 OFD&#xff08;ofdrw-conterver&#xff09;3.1 介绍&#xff1a…

Opencv+ROS实现摄像头读取处理画面信息

一、工具 ubuntu18.04 ROSopencv2 编译器&#xff1a;Visual Studio Code 二、原理 图像信息 ROS数据形式&#xff1a;sensor_msgs::Image OpenCV数据形式&#xff1a;cv:Mat 通过cv_bridge()函数进行ROS向opencv转换 cv_bridge是在ROS图像消息和OpenCV图像之间进行转…

【MySQL — 数据库基础】MySQL的安装与配置 & 数据库简单介绍

数据库基础 本节目标 掌握关系型数据库&#xff0c;数据库的作用掌握在Windows和Linux系统下安装MySQL数据库了解客户端工具的基本使用和SQL分类了解MySQL架构和存储引擎 1. 数据库的安装与配置 1.1 确认MYSQL版本 处理无法在 cmd 中使用 mysql 命令的情况&a…

shell编程基础笔记

目录 echo改字体颜色和字体背景颜色 bash基本功能&#xff1a; 运行方式&#xff1a;推荐使用第二种方法 变量类型 字符串处理&#xff1a; 条件判断&#xff1a;&#xff08;使用echo $?来判断条件结果&#xff0c;0为true&#xff0c;1为false&#xff09; 条件语句&a…

maxun爬虫工具docker搭建

思路来源开源无代码网络数据提取平台Maxun 先把代码克隆到本地&#xff08;只有第一次需要&#xff09; git clone https://github.com/getmaxun/maxun.git 转到maxun目录 cd maxun 启动容器 docker-compose --env-file .env up -d 成功启动六个容器 网址 http://local…

redis揭秘-redis01-redis单例与集群安装总结

文章目录 【README】【1】安装单机【1.1】安装环境【1.2】安装步骤 【2】redis集群主从模式配置【2.1】集群架构【2.2】redis集群主从模式搭建步骤【2.3】redis集群主从模式的问题&#xff08;单点故障问题&#xff09; 【3】redis集群哨兵模式配置【3.1】集群架构【3.2】redis…

构建高可用系统设计OpenStack、Docker、Mesos和Kubernetes(简称K8s)

如果构建高可用、高并发、高效运维的大型系统 大型系统架构设计包括业务层设计、服务层设计、基础架层设计、存储层设计、网络层协同设计来完成。 一、业务层 根据主要业务范畴的分类和特征提取&#xff0c;抽象出独立的业务系统&#xff0c;分别统计系统的用户角色群体、访…

mrRobot解题过程

一、靶场环境需要桥接网络 不建议使用校园网&#xff0c;因为使用校园网进行主机探索的时候会出现数不完的主机。 arp-scan -l若是流量少只能用校园网&#xff0c;便在这里看靶机ip 二、端口扫描 我习惯用fscan了&#xff08;需要自己安装&#xff09;&#xff0c;你们用nma…

解决“ VMware Tools for Windows Vista and later“报错问题

今天&#xff0c;在Win7虚拟机上安装VMware Tools&#xff0c;报"VMware Tools for Windows Vista and later"证书错误&#xff0c;如图(1)所示&#xff1a; 图(1) 虚拟机报" VMware Tools for Windows Vista and later"证书错误 问题原因&#xff1a;VMwa…

C-操作符

操作符种类 在C语言中&#xff0c;操作符有以下几种&#xff1a; 算术操作符 移位操作符 位操作符 逻辑操作符 条件操作符 逗号表达式 下标引用&#xff0c;函数调用 拓展&#xff1a;整型提升 我们介绍常用的几个 算术操作符 &#xff08;加&#xff09;&#xff…

时频转换 | Matlab基于S变换S-transform一维数据转二维图像方法

目录 基本介绍程序设计参考资料获取方式基本介绍 时频转换 | Matlab基于S变换S-transform一维数据转二维图像方法 程序设计 clear clc % close all load x.mat % 导入数据 x =

物联网——WatchDog(监听器)

看门狗简介 独立看门狗框图 看门狗原理&#xff1a;定时器溢出&#xff0c;产生系统复位信号&#xff1b;若定时‘喂狗’则不产生系统复位信号 定时中断基本结构&#xff08;对比&#xff09; IWDG键寄存器 独立看门狗超时时间 WWDG(窗口看门狗) WWDG特性 WWDG超时时间 由于…

Socket编程:UDP网络编程项目

目录 一、回显服务器 二、翻译器 三、聊天室 一、回显服务器 项目介绍&#xff1a;使用UDPIPv4协议进行Linux网络编程&#xff0c;实现回显服务器和客户端 功能介绍&#xff1a;客户端发送数据&#xff0c;经过服务端再返回到客户端&#xff0c;输出数据 源代码&#xff1…

Hbase2.2.7集群部署

环境说明 准备三台服务器&#xff0c;分别为&#xff1a;bigdata141&#xff08;作为Hbase主节点&#xff09;、bigdata142、bigdata143确保hadoop和zookeeper集群都先启动好我这边的hadoop版本为3.2.0&#xff0c;zookeeper版本为3.5.8 下载安装包 下载链接&#xff1a;In…

STM32 BootLoader 刷新项目 (十二) Option Byte之FLASH_OPTCR-命令0x58

STM32 BootLoader 刷新项目 (十二) Option Byte之FLASH_OPTCR-命令0x58 STM32F407芯片的OPTION Byte全面解析 STM32F407芯片是STMicroelectronics推出的一款功能强大的微控制器&#xff0c;广泛应用于工业控制、通信和消费电子等领域。其中&#xff0c;OPTION Byte&#xff0…

Matlab 绘制雷达图像完全案例和官方教程(亲测)

首先上官方教程链接 polarplothttps://ww2.mathworks.cn/help/matlab/ref/polarplot.html 上实例 % 定义角度向量和径向向量 theta linspace(0, 2*pi, 5); r1 [1, 2, 1.5, 2.5, 1]; r2 [2, 1, 2.5, 1.5, 2];% 绘制两个雷达图 polarplot(theta, r1, r-, LineWidth, 2); hold …

【C/C++】内存管理详解:从new/delete到智能指针的全面解析

文章目录 更多文章C/C中的传统内存管理方式new和delete运算符malloc和free函数传统内存管理的弊端 智能指针的崛起智能指针的定义与作用C11引入的标准智能指针 详解C标准智能指针std::unique_ptr特点使用方法适用场景 std::shared_ptr特点使用方法适用场景 std::weak_ptr特点使…

Python实现2048小游戏

2048是一个单人益智游戏&#xff0c;目标是移动和合并数字&#xff0c;以达到2048。 1. 实现效果 Python实现2048小游戏 2. 游戏规则 简单地理解一下规则 基本规则&#xff1a; 4x4棋盘&#xff0c;每个格可包含一个2的倍数的数字&#xff0c;初始时为空&#xff0c;表示0。…