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

news2024/12/23 11:04:09

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.coloradmin.cn/o/1301970.html

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

相关文章

SocialSelling社交销售1+5+1方法论系列:社交销售基础思维

社交销售是一个融合系统、个人与组织的营销销售模式&#xff0c;对于企业和销售个体来说&#xff0c;做好这件事首先是理解其次是实操。近期SocialSelling社交销售151方法论系列内容中&#xff0c;我们将对其进行系统阐述。 本篇将侧重151方法论中的第一个“1”&#xff1a;社…

C++ Qt开发:PushButton按钮组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍QPushButton按钮组件的常用方法及灵活运用。 …

【广州华锐互动】AR昆虫在线教学软件:增强现实技术带你近距离探索微观世界

随着科技的不断发展&#xff0c;教育方式也在不断创新。在这个信息爆炸的时代&#xff0c;传统的教育方式已经无法满足人们对知识的渴望。为了让孩子们更好地了解自然界的奥秘&#xff0c;一款名为“AR昆虫在线教学软件”的应用程序应运而生&#xff0c;它将带领孩子们踏上一段…

gpu版本的GNN的demo

1、当涉及到在GPU上运行图神经网络&#xff08;GNN&#xff09;时&#xff0c;通常使用深度学习框架&#xff0c;如PyTorch或TensorFlow。在这里&#xff0c;我将为您提供一个使用PyTorch Geometric库实现GNN的简单示例。 首先&#xff0c;确保您已经安装了PyTorch和PyTorch G…

dockerfile:创建镜像的方式,船舰自定义的镜像

dockerfile&#xff1a;创建镜像的方式&#xff0c;船舰自定义的镜像 包括配置文件&#xff0c;挂载点&#xff0c;对外暴露的端口&#xff0c;设置环境变量 docker创建镜像的方式 1、基于已有镜像进行创建。 根据官方提供的镜像源&#xff0c;创建镜像&#xff0c;然后拉起…

IT鄙视链:码农之间的情感大戏与编程语言间的较量

在IT圈&#xff0c;茶余饭后的谈资总离不开技术、产品、市场和那些看似高深莫测的“鄙视链”。这些鄙视链&#xff0c;就像一场没有硝烟的战争&#xff0c;把原本应该和谐交流的技术社区变成了一场争夺鄙视链顶端的激战。今天&#xff0c;就让我来为您揭示这个神秘的IT鄙视链。…

CSS 实现丝滑动画

效果展示 CSS 知识点 animation 综合运用 页面整体布局 <div class"box"><div class"circle"></div> </div>编写基础样式 .box {position: relative;width: 400px;height: 400px;border: 80px solid transparent;border-left:…

JVM虚拟机系统性学习-类加载子系统

类加载子系统 类加载的时机 类加载的时机主要有 4 个&#xff1a; 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时&#xff0c;如果对应的类没有初始化&#xff0c;则要先进行初始化 new 关键字创建对象时读取或设置一个类型的静态字段时&#xff08;被 …

12.10_黑马数据结构与算法笔记Java

目录 058 链表 e10 判环算法1 thinking&#xff1a;什么是空指针&#xff1f; 058 链表 e10 判环算法2 059 数组 e01 合并有序数组1 059 数组 e01 合并有序数组2 060 队列 链表实现1 061 队列 链表实现2 062 队列 环形数组实现 方法1-1 063 队列 环形数组实现 方法1-2…

CV计算机视觉每日开源代码Paper with code速览-2023.12.5

点击计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构&#xff1a;Transformer】GIFT: Generative Interpretable Fine-Tuning Transformers 论文地址&#xff1a;https://arxiv.org…

计算机网络——期末考试复习资料

什么是计算机网络 将地理位置不同的具有独立功能的多台计算机及其外部设备通过通信线路和通信设备连接起来&#xff1b;实现资源共享和数据传递的计算机的系统。 三种交换方式 报文交换&#xff1a;路由器转发报文&#xff1b; 电路交换&#xff1a;建立一对一电路 分组交换&a…

carla安装中的问题

1、carla carla安装完后&#xff0c;需要使用python调用API去更换地图&#xff0c;增加车辆等 使用Python调用API过程中可能会报错&#xff1a; 报错1&#xff1a;carla API&#xff08;Carla包&#xff09;版本不对 **解决方法&#xff1a;**需要将这个目录下的三个文件拷…

IDEA已经导入了jar包 还是提示找不到类(解决!!!)

项目代码check到本地,导入到idea中后,编译的时候很多类都报错了,打开发现有些框架中的类找不到。 报错:xxxx程序包找不到,xxxx类找不到 类似我框起来的地方是 报红的,utils这个包都找不到 解决方法: 网上1: 项目是依赖了这个jar包的,打开项目配置,查看依赖树: id…

2023.12.9 关于 Spring Boot 事务传播机制详解

目录 事务传播机制 七大事务传播机制 支持当前调用链上的事务 Propagation.REQUIRED Propagation.SUPPORTS Propagation.MANDATORY 不支持当前调用链上的事务 Propagation.REQUIRES_NEW Propagation.NOT_SUPPORTED Propagation.NEVER 嵌套事务 Propagation.NESTED…

优化您的Mac电脑风扇控制体验 - 尝试Macs Fan Control Pro!

在日常使用Mac电脑过程中&#xff0c;我们经常会遇到电脑发热的问题&#xff0c;特别是在运行大型软件或进行高负载任务时。为了保护电脑硬件&#xff0c;一个高效且可靠的风扇控制软件是必不可少的。 Macs Fan Control Pro是一款专为Mac电脑设计的风扇控制软件&#xff0c;它…

区块链技术是什么?解析其基本原理及应用

区块链技术的基本原理 在数字化时代的推动下&#xff0c;区块链技术作为一项革命性的创新&#xff0c;正逐渐渗透到各个领域&#xff0c;引领着未来科技的发展。区块链技术的基本原理大致可以总结为以下 4 点内容&#xff1a; 1. 去中心化&#xff1a;区块链是一个去中心化…

三(二)ts非基础类型(枚举)

数字枚举 使用enum定义一个枚举类型 enum Color {red,yellow,blue } let clr: Color Color.red如上面代码中&#xff0c;我们定义了一个关于颜色的枚举类型&#xff0c;里面的值会从0开始依次递增&#xff0c;也就是说Color.red为0&#xff0c;Color.yellow为1依次类推。当然…

渲染技术在虚拟仿真中的应用

虚拟仿真&#xff08;Virtual Reality&#xff09;是一种仿真技术&#xff0c;它使用计算机生成一个虚拟世界&#xff0c;用户可以通过各种传感通道与这个虚拟世界进行自然的交互。虚拟仿真技术可以创建和体验虚拟世界&#xff0c;使用户可以像在真实世界中一样进行操作和体验。…

Python - 深夜数据结构与算法之 ArrayList

目录 一.引言 二.ArrayList 介绍 1.List 2.Linked List 3.Skip List 三.经典算法实战 1.Two-Sum [1] 2.Three-Sum [15] 3.Merge-Two-Sorted-List [21] 4.Remove-Duplicates-From-Sorted-Array [26] 5.Plus-One [66] 6.Rotate-Array [189] 7. Move-Zero [283] 四.…

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

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