MySQL行锁范围分析(行锁、间隙锁、临键锁)

MySQL 中锁的概念

排它锁(Exclusive Lock)

X 锁,也称为写锁,若事务T对对象A加上X锁,则只允许T读取和修改A,其他任何事物都不能再对A 加任何锁,直到T释放A上的锁。
SELECT…FOR UPDATE 对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。

共享锁(Shared Lock)

**S 锁,**也称为读锁,若事务T对数据对象A加上S锁,则事务T可以读A,但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。
SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁,其他事务可以向被锁定 的行加S锁,但是如果加X锁,则会被阻塞。

活锁

事务T1封锁了R,T2又请求封锁R,于是T2等待,T3也请求封锁R,当T1释放了R 上的锁,系统首先批准了T3的请求,T2继续等待,这就是活锁。

死锁

事务T1封锁了R1,T2封锁了R2,T1又请求封锁R2,因为T2已经封锁了R2,于是T1等待T2释放R2上的锁,接着T2又申请封锁R1,因为T1已经封锁了R1,T2只能等待T1释放R1上的锁,这就是死锁。
解决死锁的方法
一次封锁法 每个事务必须将所有要使用的数据全部加锁,否则就不能执行,弊端 加大封锁范围,降低了并发速度。

乐观锁

总是假设最好的情况,在事务提交前不会对数据进行锁定,而是在更新数据时会进行版本或时间戳的比较,以确定数据是否被其他事务修改过。如果数据没有被修改,则允许提交;如果数据被修改,则需要进行冲突解决

悲观锁

总是假设最坏的情况,在整个事务过程中,假设其他事务会对数据进行修改,因此在读取或修改数据时,会先对数据进行锁定,以防止其他事务对数据进行干扰(排它锁、共享锁都是悲观锁,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程

MySQL 行锁加锁的分析

版本使用 MySQL 8.2.0
MySQL InnoDB 中支持三种行锁的方式:行锁(Record Lock)、间隙锁(Gap Lock)、临键锁(Next-Key Lock),默认加的是临键锁,但是会根据不同的查询条件进行优化。创建一个 user 表用来测试,表中 id 是主键索引,name 是唯一索引,salary 是普通索引,gender 没有索引。

idnamesalarygender
10惠月48000
20光济50000
30杰霖55000
40紫妤60000
50娜溱70000

创建表并插入数据

CREATE TABLE `user`  (`id` int(11) NOT NULL,`name` varchar(255) DEFAULT NULL,`salary` int DEFAULT NULL,`gender` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE,INDEX `salary`(`salary`) USING BTREE,UNIQUE INDEX `name`(`name` ASC) USING BTREE
);INSERT INTO `user` VALUES (10, '惠月', 48000, '女');
INSERT INTO `user` VALUES (20, '光济', 50000, '男');
INSERT INTO `user` VALUES (30, '杰霖', 55000, '男');
INSERT INTO `user` VALUES (40, '紫妤', 62000, '女');
INSERT INTO `user` VALUES (50, '娜溱', 75000, '女');

加锁情况

-- 普通的select查询是快照读,不加锁
SELECT * FROM user WHERE id=30;
-- 查询时给主键索引加S共享锁时,是当前读
SELECT * FROM user WHERE id=30 LOCK IN SHARE MODE;
-- 查询时加 X排他锁,为当前读
SELECT * FROM user WHERE id=30 FOR UPDATE

执行 SELECT * FROM … FOR UPDATE 会对表加上 IX 写意向锁,表示有可能会对这些记录进行写操作,并且给记录加一个X,REC_NOT_GAP,锁定了该条数据。 执行SELECT * FROM … FOR SHARE 会对表加上一个 IS 读意向锁,并且会给记录加一个S,REC_NOT_GAP。

主键索引

主索引等值查询,数据存在的情况

事务 1

BEGIN;
SELECT * FROM user WHERE id=30 FOR UPDATE;
-- SELECT * FROM user WHERE id=40 FOR SHARE;
-- ROLLBACK

查看锁的情况

-- mysql 8
SELECT * FROM performance_schema.data_locks;-- mysql 5.7
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

image.png
1、表锁是意向写锁
2、数据加行锁
各字段意思:
INDEX_NAME 锁定索引的名称 PRIMARY 说明是主键索引
LOCK_TYPE 锁的类型,RECORD 行锁 、 TABLE 表锁
LOCK_MODE 锁的模式,IS 读意向锁、IX 写意向锁、S 读锁,又称共享锁、X 写锁,又称排它锁、GAP 间隙锁。
**LOCK_DATA **要锁定的数据,当 LOCK_TYPE 是 RECORD行锁时。当锁在主键索引上时,显示主键索的值。当锁是在辅助索引上时,显示主索引和辅助索引的值。

LOCK_MODELOCK_DATA锁范围
X,REC_NOT_GAP40id=40 行锁
X,GAP40id=40 间隙锁,不包含 40(前开后开)
X40id=40 临键锁,包含 40(前开后闭)

事务 2
1、会对主索引 id=30 添加行锁

BEGIN;
-- 更新会失败,因为事务 1 对 id=30 加行锁。
UPDATE user SET salary = 56000 WHERE id = 30;

主索引等值查询,数据不存在的情况

事务 1

BEGIN;
SELECT * FROM user WHERE id=31 FOR UPDATE; -- 数据库中没有id=30的记录

查看加锁情况
image.png
1、表加的是意向写锁
2、id 加的是 GAP Lock,范围是(30, 40)
注意
LOCK_MODE 是 X,GAP 表示间隙锁,LOCK_DATA 是 40 表示锁定的范围是在 id 为 40 之前的间隙
事务 2
1、会锁住主索引 id=31 所在的间隙

BEGIN;
-- 可以执行成功
UPDATE `bostore`.`user` SET `salary` = 56000.00 WHERE `id` = 30;
UPDATE `bostore`.`user` SET `salary` = 63000.00 WHERE `id` = 40;
-- 执行失败
INSERT INTO `bostore`.`user` VALUES (33, '六零', 68000.00, '女');

主索引范围查询,前闭后开情况

事务 1

BEGIN;
SELECT * FROM user WHERE id>=30 AND id<33 FOR UPDATE;

查看锁情况
image.png
1、 表示 IX 意向写锁
2、id=30 是行锁
3、id=40 加的是 GAP Lock,范围是(30, 40)
事务 2

BEGIN;
-- 会阻塞
UPDATE user SET salary = 57000.00 WHERE id = 30;
INSERT INTO user VALUES (35, '六零', 68000.00, '女');
INSERT INTO user VALUES (33, '合吧', 64000.00, '女');
-- 不会阻塞
UPDATE user SET salary = 63000.00 WHERE id = 40;

主索引范围查询,前开后闭情况

事务 1

BEGIN;
SELECT * FROM user WHERE id>30 AND id<=40 FOR UPDATE;

查看锁情况
image.png
1、表加的是意向写锁
2、id=40 加 NEXT-Key Lock,范围是(30, 40]
事务 2

BEGIN;
-- 会阻塞
UPDATE user SET salary = 63000 WHERE id = 40;
INSERT INTO user VALUES (35, '六零', 68000, '女');
INSERT INTO user VALUES (33, '合吧', 64000, '女');-- 不会阻塞
UPDATE user SET salary = 57000 WHERE id = 30;
UPDATE user SET salary = 78000 WHERE id = 50;
INSERT INTO user VALUES (53, '考拉', 84000, '女');

普通索引

普通索引(普通索引只针对表中的单一列进行索引,普通索引可以是唯一的,也可以不唯一,普通索引对于等值查询(例如WHERE column = value)和范围查询(例如WHERE column > value)都能提供较好的性能提升)

普通索引等值查询,数据存在的情况

事务 1

BEGIN;
SELECT * FROM user WHERE salary = 62000 FOR UPDATE;

查看锁情况
image.png
1、 表加意向写锁 IX
2、 索引salary加临键锁,范围是(55000, 62000]
3、 主键 id = 40 加行锁
4、 索引salary加间隙锁,范围是(62000, 75000)
事务 2
1、 主键 id=40 加了行锁,不能更新和删除

-- 修改id=40有行锁会阻塞
UPDATE user SET salary = 63000 WHERE id = 40;
UPDATE user SET name="紫是" where salary = 62000;

2、salary 在(55000, 62000] 范围加了 NEXT-Key Lock(针对该范围的 id 也会加锁),insert 时salary 在此范围,会阻塞
image.png
3、salary 在(62000, 75000)范围加了 GAP Lock(避免幻读),insert 时salary 在此范围,会阻塞
image.png
4、 插入 salary=55000时,id<30可以不阻塞,id>30会阻塞

-- id=40  salary=62000 之前有临键锁(55000, 62000]
-- 是对salary的锁,但是整个区间都会被锁住包括主索引id
INSERT INTO user VALUES (35, '六零', 55000, '女'); -- 阻塞
INSERT INTO user VALUES (51, '哈西', 55000, '女'); -- 阻塞
-- id=30  salary=55000 之前没有间隙锁
INSERT INTO user VALUES (29, '湖西', 55000, '女'); -- 不阻塞

5、 插入 salary=62000时,会阻塞

INSERT INTO user VALUES (39, '哈子', 62000, '女');
INSERT INTO user VALUES (44, '靠是', 62000, '女');
INSERT INTO user VALUES (55, '西欧', 62000, '女');
-- 自增id时也是会阻塞
INSERT INTO `bostore`.`user`(`name`, `salary`, `gender`) VALUES ('学律', 62000, '女');

6、插入 salary=75000时,id<50 会阻塞,id>50 不阻塞

-- LOCK_MODE为X,GAP 
-- LOCAK_DATA为75000, 50 表示 要插入salary为75000,id<50时会加锁,即会阻塞
INSERT INTO user VALUES (29, '合吧', 75000, '女');
-- id > 50 不会阻塞
INSERT INTO user VALUES (51, '欧下', 75000, '女');

7、当salary 不在(55000, 62000] 和(62000, 75000)范围时,id 不会加锁

INSERT INTO user VALUES (31, '湖西', 54000, '女');
INSERT INTO user VALUES (49, '离下', 54000, '女');
INSERT INTO user VALUES (45, '的大', 76000, '女');
UPDATE user SET salary = 78000 WHERE id = 50;-- id < 30 和 salary < 55000 不阻塞
INSERT INTO user VALUES (29, '六零', 50000, '女');
-- id > 50 和 salary > 75000 不阻塞
INSERT INTO user VALUES (63, '合吧', 94000, '女');

普通索引等值查询,数据不存在的情况

事务 1

BEGIN;
SELECT * FROM user WHERE salary = 60000 FOR UPDATE;

查看锁情况
image.png
1、表加意向写锁
2、salary 加间隙锁,范围是(55000, 62000)
事务 2
1、salary 在(55000, 62000)范围加了 GAP Lock,insert 时salary 在此范围,会阻塞
image.png
2、插入 salary=55000时,id<30可以不阻塞,id>30会阻塞

INSERT INTO user VALUES (35, '六零', 55000, '女'); -- 阻塞
INSERT INTO user VALUES (51, '哈西', 55000, '女'); -- 阻塞
-- id=30  salary=55000 之前没有间隙锁
INSERT INTO user VALUES (29, '湖西', 55000, '女'); -- 不阻塞

3、插入 salary=62000时,id<40 会阻塞,id>40 不阻塞

-- id < 40 会阻塞
INSERT INTO user VALUES (39, '合吧', 62000, '女');
-- id > 40 不会阻塞
INSERT INTO user VALUES (41, '欧下', 62000, '女');

4、当 salary 不在(55000, 62000),id 不会加锁

INSERT INTO user VALUES (31, '湖西', 54000, '女');
INSERT INTO user VALUES (39, '离下', 63000, '女');
UPDATE user SET salary = 63000 WHERE id = 40;-- id < 30 和 salary < 55000 不阻塞
INSERT INTO user VALUES (29, '六零', 50000, '女');
-- id > 40 和 salary > 62000 不阻塞
INSERT INTO user VALUES (41, '合吧', 65000, '女');

普通索引范围查询,前闭后开的情况

事务 1

BEGIN;
SELECT * FROM user WHERE salary>=55000 AND salary<62000 FOR UPDATE;

查看锁情况
image.png
1、表加意向写锁
2、salary 加 NEXT-Key Lock 范围是(50000, 55000]
3、salary 加 NEXT-Key Lock 范围是(55000, 62000]
4、id=30 加行锁
事务 2
1、 插入 salary=50000时,id<20可以不阻塞,id>20会阻塞

INSERT INTO user VALUES (19, '六零', 50000, '女'); -- 不阻塞
INSERT INTO user VALUES (21, '哈西', 50000, '女'); -- 阻塞
INSERT INTO user VALUES (41, '湖西', 50000, '女'); -- 阻塞

2、 插入 salary=55000时,会阻塞

INSERT INTO user VALUES (29, '哈子', 55000, '女');
INSERT INTO user VALUES (35, '靠是', 55000, '女');
INSERT INTO user VALUES (44, '西欧', 55000, '女');
-- 自增id时也是会阻塞
INSERT INTO `bostore`.`user`(`name`, `salary`, `gender`) VALUES ('学律', 55000, '女');

3、 插入 salary=62000时,id<40 会阻塞,id>40 不阻塞

-- 阻塞
INSERT INTO user VALUES (39, '合吧', 62000, '女');
-- 不阻塞
INSERT INTO user VALUES (41, '欧下', 62000, '女');

4、当salary 不在(50000, 55000] 和(55000, 62000]范围时,id 不会加锁

INSERT INTO user VALUES (31, '湖西', 44000, '女');
INSERT INTO user VALUES (49, '离下', 44000, '女');
INSERT INTO user VALUES (45, '的大', 66000, '女');-- id < 20 和 salary < 50000 不阻塞
INSERT INTO user VALUES (19, '六零', 40000, '女');
-- id > 40 和 salary > 62000 不阻塞
INSERT INTO user VALUES (53, '合吧', 94000, '女');

5、id=30 加行锁,不能删除和更新

UPDATE user SET salary = 56000 WHERE id = 30;
UPDATE user SET name="紫下" where salary = 55000;

普通索引范围查询,前开后闭的情况

事务 1

BEGIN;
SELECT * FROM user WHERE salary>55000 AND salary<=62000 FOR UPDATE;

查看锁情况
image.png
1、表加意向写锁
2、salary 加 NEXT-Key Lock 范围是(55000, 62000]
3、salary 加 NEXT-Key Lock 范围是(62000, 75000]
4、id=40 加行锁
事务 2 的加锁情况和上面类似

没有索引的情况

BEGIN;
SELECT * FROM user WHERE gender='男' FOR UPDATE;

查看加锁情况
image.png
InnoDB 的锁是加上在索引上的,没有索引的时候,就会给所有的记录都加上锁 NEXT-Key Lock,相当于表锁。

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

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

相关文章

风控之Android设备指纹技术

标识性参数——Android ID、IMEI、OAID非标识性参数 非标识性参数——手机运营商 1 设备指纹 简单来讲&#xff0c;设备指纹是指用于标识出该设备的设备特征。可以是单一设备特征&#xff0c;也可以是多种设备特征的组合&#xff0c;以方便风控系统对设备的唯一性进行识别。…

产品入门第一讲:Axure的安装以及基本使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有…

未来教师行业发展前景

亲爱的老师们&#xff0c;你是否对未来教师行业的发展前景感到好奇和期待&#xff1f;作为一名老师&#xff0c;我深知教育行业的重要性和挑战&#xff0c;但同时也看到了其中蕴含的巨大机遇。 一、技术融合与在线教育 技术的飞速发展正在改变着教育的面貌。在线教育平台的崛起…

用C语言了解文件那些下 ‘流‘ 事

本篇会加入个人的所谓‘鱼式疯言’❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的&#xff0c;可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 前言 &#…

uniapp实战 —— 自定义顶部导航栏

效果预览 下图中的红框区域 范例代码 src\pages.json 配置隐藏默认顶部导航栏 "navigationStyle": "custom", // 隐藏默认顶部导航src\pages\index\components\CustomNavbar.vue 封装自定义顶部导航栏的组件&#xff08;要点在于&#xff1a;获取屏幕边界…

OpenAI在中国,申请GPT-6、GPT-7商标

根据最新商标信息显示&#xff0c;OpenAI已经在中国提交了GPT-6和GPT-7的商标注册信息&#xff0c;分类是科学仪器和网站服务两大类。申请日期是今年的11月2日&#xff0c;目前处于审核状态。 该申请由知识产权代理公司完成&#xff0c;但申请人的地址正是OpenAI在美国公司的地…

Echarts图表title使用富文本

rich中有配置的话&#xff08;如a&#xff09;使用该样式&#xff0c;没有配置样式的话&#xff08;如b&#xff09;使用外层textstyle的样式&#xff0c;textstyle没有样式的话使用默认样式 const option1 {tooltip: {trigger: "item",},title: {text: ["{a|1…

Java代码审计之SpEL表达式注入漏洞分析

文章目录 前言SpEL表达式基础基础用法安全风险案例演示 CVE-2022-22963漏洞简述环境搭建反弹shell CVE漏洞调试分析本地搭建调试分析补丁分析 总结 前言 表达式注入是 Java 安全中一类常见的能够注入命令并形成 RCE 的漏洞&#xff0c;而常见的表达式注入方式有 EL 表达式注入…

124.(leaflet篇)leaflet禁止地图移动,缩放,双击

地图之家总目录(订阅之前必须详细了解该博客) 完整代码工程包下载,运行如有问题,可“私信”博主。效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【Docker】使用docker-compose搭建django+vue工程文章

我们尝试使用docker-compose编排一个后端基于django,前端基于vue,数据库为postgresql并使用nginx进行反向代理的web工程。 工程准备 Docker 安装Docker 安装docker-compose django 在python3.7的环境下创建 修改settings.py文件 修改 将静态文件收集路径添加进 ,笔…

pip指定优先从豆瓣源下载包

对于 Unix/macOS 系统&#xff0c;使用以下命令&#xff1a; pip config set global.index-url https://pypi.douban.com/simple/ 对于 Windows 系统&#xff0c;打开命令提示符或PowerShell&#xff0c;并使用相同的命令&#xff1a; pip config set global.index-url http…

XUbuntu22.04之8款免费UML工具(一百九十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

供应链管理痛点大解析!内附解决方案

供应链是指涉及产品或服务生产、运输、分销和最终交付给客户的过程。 用一个汽车制造的例子来帮助大家理解&#xff1a; 原材料采购&#xff1a; 汽车制造商需要从供应商处采购制造汽车所需的原材料&#xff0c;例如金属、橡胶、塑料和玻璃。生产制造&#xff1a;获得原材料&…

UnoCSS 原子化开发初体验

UnoCSS 是一个即时的原子化 CSS 引擎&#xff0c;旨在灵活和可扩展。核心是不拘一格的&#xff0c;所有的 CSS 工具类都是通过预设提供的。再也不用为了取一个 classname 类名而烦恼了。 一、UnoCSS 特点 完全可定制&#xff1a;无核心工具&#xff0c;所有功能都通过预设提供…

如何公网访问内网的群晖NAS随时随地远程访问本地存储的学习资源

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

成都工业学院Web技术基础(WEB)实验六:ECMAScript基础语法

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考&#xff0c;前端变化比较大&#xff0c;按照要求&#xff0c;只能做到像&#xff0c;不能做到一模一样 3、图片和文字仅为示例&#xff0c;需要自行替换 4、如果代码不满足你的要求&#xff0c;请寻求其他的…

TwinCAT3 Modbus-TCP Client/Server使用

目录 一、环境配置和准备 1、PLC中安装TF6250-Modbus-TCP库 2、勾选TF6250的license 3、PLC工程中添加Tc2_ModbusSrv库文件 4、分别创建测试ModbusTCP测试的Server和Client程序 二、PLC作为Client端 1、设置测试电脑IP地址 2、运行MobusTCP测试工具 3、PLC端程序编写 …

Hiera实战:使用Hiera实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

可学习超图拉普拉斯算子代码

python版本&#xff1a;3.6。sklearn版本&#xff1a;scikit-learn0.19 问题1&#xff1a;ERROR: Could not build wheels for ecos, scs, which is required to install pyproject.toml-based projects| 解决办法&#xff1a;cvxpy安装过程中遇到的坑_ecos 2.0.7.post1 cp37 …

大数据技术7:基于StarRocks统一OALP实时数仓

前言&#xff1a; 大家对StarRocks 的了解可能不及 ClickHouse或者是远不及 ClickHouse 。但是大家可能听说过 Doris &#xff0c;而 StarRocks 实际上原名叫做 Doris DB &#xff0c;他相当于是一个加强版的也就是一个 Doris ,也就是说 Doris 所有的功能 StarRocks 都是有的&a…