mysql系列10—mysql锁

背景

mysql中锁机制核心是保证数据的一致性以及并发控制。锁机制的实现与存储引擎有关,本文介绍的是INNODB存储引擎的锁机制;其他存储引擎如myISAM和memory等仅支持表锁不支持行锁,不是本文关注的重点。
本文介绍mysql数据库提供的锁机制,包括共享锁和排它锁、表锁和行锁、间隙锁和next_key锁。理解本文后,有助于在不同业务场景设计出合理的索引结构。最后介绍死锁的检测和处理方式。
本文会结合案例进行介绍,表结构和数据如下所示:

CREATE TABLE `t_student` (`id`    INT(10)      NOT NULL COMMENT '学号,唯一ID',`name`  VARCHAR(50)  NOT NULL COMMENT '姓名',`score` INT(10)      NOT NULL COMMENT '分数',PRIMARY KEY (`id`) USING BTREE,INDEX `idx_score` (`score`) USING BTREE
)
ENGINE=InnoDB
;
mysql> select * from t_student;
+-----+-----------+-------+
| id  | name      | score |
+-----+-----------+-------+
|   2 | 测试2     |     2 |
|  10 | 测试10    |    10 |
| 100 | 测试100   |   100 |
| 101 | 测试101   |   101 |
| 200 | 测试200   |   200 |
+-----+-----------+-------+

1.共享锁和排他锁

mysql中加锁需要依次确定锁类型、锁粒度,即先确定是加共享锁还是排它锁,然后确定使用行锁还是表锁。
本章介绍mysql锁的类型,包括共享锁和排他锁, 定义如下:

共享锁(Share, 也称为S锁),是一种允许多个事务同时对同一数据行或资源进行读操作的锁;它保证了多个事务可以并发地读取数据,但不允许其他事务对数据进行写操作。

排他锁(Exclude, 也称为X锁)是一种独占锁,用于写操作;当一个事务对某行数据加了排他锁后,其他事务不能对该行加任何类型的锁(包括共享锁和排他锁)。

mysql引入了MVCC解决了并发读写问题,因此普通的select语句不会加锁,特殊的select语句才会加锁:

-- 共享锁
select * from table_name where ... lock in share mode;-- 排它锁
select * from table_name where ... for update;

delete、update、insert等修改修改语句会添加排它锁。

2.表锁和行锁

行锁以行为单位进行加锁;锁冲突小,并发度较高; 表锁对整个表进行加锁;锁冲突大,并发度较低。
加锁的范围由where语句确定, 通过以下三种场景进行介绍。
Note1:行锁添加在索引上,如果没有索引,会退化为表锁
案例:事务A将name='测试2'的列对应的name字段修改为’生产2’; 事务B将name='测试10'的列对应的name字段修改为’生产10’.
请添加图片描述

案例如上所示, 由于name字段上没有添加索引,所以where name = '测试2’条件的锁为表锁;此时,另一事务修改t_student中的其他记录时会阻塞。

重置数据库状态为初始状态,对name添加索引(UNIQUE INDEX unique_name(name) USING BTREE),再次执行上述案例:
请添加图片描述

由于name字段上添加了唯一索引,所以where name = '测试2’条件的锁为行锁;此时,另一事务修改t_student中的其他记录时不会阻塞。

Note2:列必须是主键或者唯一索引,否者(普通索引)加的锁是next-key锁

next-key锁请参考章节3.间隙锁和next_key锁

案例:事务A将score=200的列对应的name字段修改为’生产200’, 事务B新增一条记录(id=150,name=‘测试150’, score=150).

请添加图片描述

案例如上所示, 由于score字段为普通索引(不是主键或者唯一索引),所以where score= 200 条件的锁为next-key锁, 加锁范围为(101, 200];此时,事务B新增的列score值为150在(101, 200]范围内,因此事务B被阻塞(直到事务A提交后才会执行)。

重置数据库至初始状态,如果将 where score = 200 修改为 id = 200(或name=‘测试200’), 结果如下:
请添加图片描述

id=200只会给当前记录加锁,不会获取id=150的记录锁;因此事务B不会被阻塞。

Note3:必须是精确匹配,否者(范围、模糊查询)加的锁是间隙锁

间隙锁请参考章节3.间隙锁和next_key锁

案例:事务A将满足id<=100条件的列对应的name字段修改为’生产’, 事务B新增一条记录(id=50,name=‘测试50’, score=50), 事务C新增一条记录(id=150,name=‘测试150’, score=150).

请添加图片描述

案例如上所示, id<=100条件的锁为间隙锁, 加锁范围为(-无穷, 100];此时事务B新增的列score值为50在(-无穷, 100]范围内,因此事务B被阻塞(直到事务A提交后才会执行);而事务C新增的列score值为150,不在(-无穷, 100]范围内,因此事务C不被阻塞。

3.间隙锁和next_key锁

间隙锁: 对于一个范围而不是一条记录添加索引,当对主键或者唯一索引使用范围查询时,mysql会对这个范围加锁。在章节2的Note3中,id<=100条件的锁为间隙锁, 加锁范围为(-无穷, 100].
next_key锁: 对于通索引(非主键和唯一索引),会在一个范围加锁,称为next-key锁。next-key是一个前开后闭的区间,对于案例数据,如果需要操作score=200的数据,加锁范围为:(101,200]; 如果需要操作score=100的数据,加锁范围为:(10, 100];

mysql> select * from t_student;
+-----+-----------+-------+
| id  | name      | score |
+-----+-----------+-------+
|   2 | 测试2     |     2 |
|  10 | 测试10    |    10 |
| 100 | 测试100   |   100 |
| 101 | 测试101   |   101 |
| 200 | 测试200   |   200 |
+-----+-----------+-------+

说明:间隙锁和next_key锁通过在一个范围加锁,可以有效避免幻读的发生。

4.意向锁

略,Note: 意向锁的引入仅仅是为了提高mysql锁机制的判断效率,由Innodb内部使用(添加和释放),与前面介绍的锁无任何冲突,用户无感知(可以理解为不存在这种锁)。

5.死锁问题

mysql事务在执行过程中会根据需要获取锁,锁被其他事务占据时会持续等待(或者超时报错退出);
获取的锁在事务结束的时候才会释放,因此当事务间锁相互持有或者循环持有的情况发送时就会导致死锁:
请添加图片描述

死锁检测

mysql中存在死锁检测机制,当检测到死锁时,会自动中止其中一个事务并释放锁,被中止的事务抛出ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction的异常。

案例如下所示:

time事务A事务B
1START TRANSACTION;START TRANSACTION;
2update t_student set name=‘testA’ where id=2;
3update t_student set name=‘testB’ where id=100;
4update t_student set name=‘testA’ where id=100;
5update t_student set name=‘testB’ where id=2;
6COMMIT;COMMIT;

执行过程如下所示:

请添加图片描述

执行SHOW ENGINE INNODB STATUS;可以在"LATEST DETECTED DEADLOCK"段中查看死锁信息:

# 剔除了一些不必要信息,突出重点
------------------------
LATEST DETECTED DEADLOCK
------------------------
2025-02-07 16:33:53 139664724940544
*** (1) TRANSACTION:
TRANSACTION 38235789, MySQL thread id 12587, OS thread handle 139658703853312, query id 323778 localhost root updating
update t_student set name='testA' where id=100*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 15112 page no 4 n bits 120 index PRIMARY of table `test`.`t_student` trx id 38235789 lock_mode X locks rec but not gap Record lock, 
heap no 48 PHYSICAL RECORD【用锁X48表示】*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 15112 page no 4 n bits 120 index PRIMARY of table `test`.`t_student` trx id 38235789 lock_mode X locks rec but not gap waiting
Record lock, heap no 51 PHYSICAL RECORD【用锁X51表示】*** (2) TRANSACTION:
TRANSACTION 38235791, MySQL thread id 12588, OS thread handle 139664290703104, query id 323785 localhost root updating
update t_student set name='testB' where id=2*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 15112 page no 4 n bits 120 index PRIMARY of table `test`.`t_student` trx id 38235791 lock_mode X locks rec but not gap Record lock, 
heap no 51 PHYSICAL RECORD【用锁X51表示】*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 15112 page no 4 n bits 120 index PRIMARY of table `test`.`t_student` trx id 38235791 lock_mode X locks rec but not gap waiting Record lock,
heap no 48 PHYSICAL RECORD【用锁X48表示】*** WE ROLL BACK TRANSACTION (2)

信息比较清晰:
检测到死锁,对应两个事务标记为事务(1)和事务(2):
事务(1)的事务ID为38235789,已持有了锁X48; 然后执行update t_student set name=‘testA’ where id=100语句获取锁X51失败阻塞;
事务(2)的事务ID为38235791,已持有了锁X51; 然后执行update t_student set name=‘testB’ where id=2语句获取锁X48失败阻塞;
mysql选择回滚事务(2)以解决死锁问题。

避免死锁问题的策略

[1] 保持加锁顺序的一致性
上述案例中,如果事务A和事务B以相同的加锁顺序执行SQL语句,不会发送死锁现象;

[2] 减少事务的颗粒度
事务的锁在事务提交后才会释放,事务颗粒度越大,执行的SQL语句越多,获取的锁越多,约容易造成死锁现象;

[3] 设计合理的索引和SQL条件语句
间隙锁和next-key锁相对于行锁更容易发生死锁现象。

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

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

相关文章

Redis7——基础篇(八)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

《国密算法开发实战:从合规落地到性能优化》

前言 随着信息技术的飞速发展,信息安全已成为全球关注的焦点。在数字化时代,数据的保密性、完整性和可用性直接关系到国家、企业和个人的利益。为了保障信息安全,密码技术作为核心支撑,发挥着至关重要的作用。国密算法,即国家密码算法,是我国自主设计和推广的一系列密码…

yolov12 部署瑞芯微 rk3588、RKNN 部署工程难度小、模型推理速度快

yolov12 部署又来了。 特别说明&#xff1a;如有侵权告知删除&#xff0c;谢谢。 完整代码&#xff1a;包括onnx转rknn和测试代码、rknn板端部署C代码&#xff1a; 【onnx转rknn和测试代码】 【rknn板端部署C代码】 1 模型训练 yolov12训练官方开源的已经非常详细了&#…

windows本地化部署Dify+Deepseek

Windows本地化部署DifyDeepseek 一、下载Docker 前往 Docker 官网 下载 Docker Desktop&#xff0c;按序安装。 1.1启用WSL 打开本机的控制面板>程序>启用或关闭 Windows 功能,勾选: Linux 的 Windows 子系统虚拟机平台&#xff08;若无该选择则勾选 Hyper-V &#…

使用Spring Boot与达梦数据库(DM)进行多数据源配置及MyBatis Plus集成

使用Spring Boot与达梦数据库(DM)进行多数据源配置及MyBatis Plus集成 在现代企业级应用开发中&#xff0c;处理多个数据源是一个常见的需求。本文将详细介绍如何使用Spring Boot结合达梦数据库&#xff08;DM&#xff09;&#xff0c;并通过MyBatis Plus来简化数据库操作&…

第二十四:5.2【搭建 pinia 环境】axios 异步调用数据

第一步安装&#xff1a;npm install pinia 第二步&#xff1a;操作src/main.ts 改变里面的值的信息&#xff1a; <div class"count"><h2>当前求和为&#xff1a;{{ sum }}</h2><select v-model.number"n">  // .number 这里是…

使用 DeepSeek 生成流程图、甘特图与思维导图:结合 Typora 和 XMind 的高效工作流

在现代工作与学习中&#xff0c;可视化工具如流程图、甘特图和思维导图能够极大地提升信息整理与表达的效率。本文将详细介绍如何使用 DeepSeek 生成 Mermaid 文本&#xff0c;结合 Typora 快速生成流程图和甘特图&#xff0c;并通过 Markdown 格式生成思维导图&#xff0c;最终…

DeepSeek 开源周:第五天 - Fire-Flyer 文件系统(3FS)

&#xff08;下面文字主要由 Grok 3 协助生成&#xff09; 概述 Deepseek 今天开源的 Fire-Flyer 文件系统&#xff08;3FS&#xff09;是一个高性能分布式文件系统&#xff0c;专门为 AI 训练和推理设计。研究表明&#xff0c;它解决了 AI 工作负载中处理海量数据的高效存储需…

【笔记】论文阅读方法(AI大模型)

1 为什么读论文 构建知识体系&#xff1a;通过Related Works快速了解该方向研究现状&#xff0c;追踪经典论文 紧跟前沿技术&#xff1a;了解领域内新技术及效果&#xff0c;快速借鉴到自身项目 培养科研逻辑&#xff1a;熟悉论文体系&#xff0c;了解如何创造新事物&#x…

【数据集】ACM数据集

ACM&#xff08;Association for Computing Machinery&#xff09;数据集是计算机科学领域常用于研究学术论文、作者关系、引文网络、推荐系统、图神经网络&#xff08;GNN&#xff09;等任务的数据集之一。该数据集通常包含学术论文、作者、研究领域以及它们之间的关系&#x…

SQL server配置ODBC数据源(本地和服务器)

本地配置 1. 控制面板中找到系统ODBC数据源&#xff08;打开控制面板直接搜&#xff09; 2. 选择“系统DSN”&#xff0c;点击“添加” 3. 选择“SQL server” 4. 名称和描述自己填&#xff0c;服务器选择本机设备名称 5. 选择ID和密码验证&#xff0c;并填写本地SQL server登…

使用 Postman 访问 Keycloak 端点

1. 引言 在本教程中&#xff0c;我们将首先快速回顾 OAuth 2.0、OpenID 和 Keycloak。然后&#xff0c;我们将了解 Keycloak REST API 以及如何在 Postman 中调用它们。 2. OAuth 2.0 OAuth 2.0 是一个授权框架&#xff0c;它允许经过身份验证的用户通过令牌向第三方授予访问…

文生图开源模型发展史(2014-2025年)

文生图开源模型的发展历程是一段充满技术革新、社区生态繁荣与商业化竞争的多维度演进史。 一、技术萌芽期&#xff08;2014-2020年&#xff09; 核心突破 2014年&#xff1a;GAN&#xff08;生成对抗网络&#xff09;诞生&#xff0c;首次实现数据驱动式图像生成&#xff0…

微服务学习(2):实现SpringAMQP对RabbitMQ的消息收发

目录 SpringAMQP是什么 为什么采用SpringAMQP SpringAMQP应用 准备springBoot工程 实现消息发送 SpringAMQP是什么 Spring AMQP是Spring框架下用于简化AMQP&#xff08;高级消息队列协议&#xff09;应用开发的一套工具集&#xff0c;主要针对RabbitMQ等消息中间件的集成…

AI人工智能机器学习之神经网络

1、概要 本篇学习AI人工智能机器学习之神经网络&#xff0c;以MLPClassifier和MLPRegressor为例&#xff0c;从代码层面讲述最常用的神经网络模型MLP。 2、神经网络 - 简介 在 Scikit-learn 中&#xff0c;神经网络是通过 sklearn.neural_network 模块提供的。最常用的神经网…

WPF高级 | WPF 与数据库交互:连接、查询与数据更新

WPF高级 | WPF 与数据库交互&#xff1a;连接、查询与数据更新 前言一、数据库交互基础概念1.1 数据库简介1.2 数据访问技术 二、WPF 与数据库连接2.1 连接字符串2.2 建立连接 三、WPF 中的数据查询3.1 使用ADO.NET进行数据查询3.2 使用 Entity Framework 进行数据查询3.3 使用…

【ESP32S3接入讯飞在线语音识别】

【ESP32S3接入讯飞在线语音识别】 1. 前言1.1 步骤概括1.2 硬件介绍1.3 接线2. 操作流程2.1 创建语音识别应用2.2 记录API秘钥3. JSON语音接入api3.1 JSON格式3.2 交互流程3.2 ESP32S3 Sense接入代码1. 核心功能2. 主要模块3. 工作流程4. 典型应用场景5. 关键技术点6. 待完善功…

学生管理前端

文章目录 首页student.html查询功能 首页 SpringBoot前端html页面放在static文件夹下&#xff1a;/src/main/resources/static 默认首页为index.html&#xff0c;我们可以用两个超链接或者两个button跳转到对应的页面。这里只是单纯的跳转页面&#xff0c;不需要提交表单等其…

(动态规划 最长递增的子序列)leetcode 300

这道题我第一眼反应就是暴力&#xff0c;但是暴力的话就是n*n-1*n-2*...n-(n-1) 也就是O(n^n)dfs做绝对超时 贪心也不行&#xff0c;这里是子序列&#xff0c;要考虑在ni的范围内考虑多种路线取最优&#xff0c;所以用动态规划 如何用动态规划呢&#xff1f; 答&#xff1a;…

RabbitMQ系列(六)基本概念之Routing Key

在 RabbitMQ 中&#xff0c;Routing Key&#xff08;路由键&#xff09; 是用于将消息从交换机&#xff08;Exchange&#xff09;路由到指定队列&#xff08;Queue&#xff09;的关键参数。其核心作用是通过特定规则匹配绑定关系&#xff0c;确保消息被正确分发。以下是其核心机…