服了!DELETE 同一行记录也会造成死锁---图文解析

news2024/9/26 1:21:54

服了!DELETE 同一行记录也会造成死锁!!

作者:转转技术团队
链接:https://juejin.cn/post/7387227689319563290
来源:稀土掘金

MySQL 锁回顾

img

共享锁

使用共享锁(Shared Lock)时,它允许持有该锁的事务读取一行数据,但不允许对其进行更新或删除。这种锁的主要目的是防止其他事务修改被锁定的数据。

举个例子:共享锁(Shared Lock) 就像是大家一起看电视,但只能看,不能改变频道。这意味着多个事务可以同时读取同一份数据,但不能修改它。共享锁适用于只读操作,比如查看账户余额或者商品库存。

CREATE TABLE employees (
  emp_no INT NOT NULL,
  birth_date DATE NOT NULL,
  first_name VARCHAR(14) NOT NULL,
  last_name VARCHAR(16) NOT NULL,
  gender ENUM('M','F') NOT NULL,
  hire_date DATE NOT NULL,
  middle_name VARCHAR(14),
  PRIMARY KEY (emp_no)
);

INSERT INTO `employees` VALUES (101, '1990-01-15', 'John', 'Doe', 'M', '2020-05-10', 'Michael', 2000.00);
INSERT INTO `employees` VALUES (102, '1988-03-20', 'Jane', 'Smith', 'F', '2019-12-01', 'Elizabeth', 1500.00);
INSERT INTO `employees` VALUES (103, '1995-07-05', 'Robert', 'Johnson', 'M', '2021-02-18', 'William', 1800.00);

-- 在事务1中获取共享锁
START TRANSACTION;
SELECT salary FROM employees WHERE emp_no = 101 LOCK IN SHARE MODE;

-- 此时其他事务可以读取 salary,但不能修改或删除

-- 在事务2中尝试修改 salary(会被阻塞)
UPDATE employees SET salary = 6000 WHERE emp_no = 101;
-- 这里会等待,直到事务1释放共享锁

-- 在事务1中继续操作或提交
COMMIT;

共享锁,启动两个事务,事务1启动后,可以正常看到具体的数值:

BEGIN;
SELECT salary FROM employees WHERE emp_no = 101 LOCK IN SHARE MODE;
--COMMIT;

在这里插入图片描述

新启动一个事务查询同一行,发现可以正常查询:

在这里插入图片描述

排他锁(Exclusive Lock) 就像是你独占一台电视,可以随便换频道,甚至关掉。其他人想看电视,需要你交出电视控制权才可以,否则看都不能看。排他锁用于数据修改操作,比如更新账户余额、添加新订单或者删除记录。只有一个事务能持有排他锁,其他事务必须等待它释放锁后才能操作。

事务1,可以看到查询结果,但没有提交,所以事务无法结束。

在这里插入图片描述

事务2,无法看到查询结果,因为事务1独占排他锁(事务2模拟的时候不要执行COMMIT):

BEGIN;
SELECT salary FROM employees WHERE emp_no = 101 FOR UPDATE;
COMMIT;

在这里插入图片描述

提交事务1后,事务2的查询结果才能看到:

在这里插入图片描述

在这里插入图片描述

表锁

意向锁:意向锁分为意向共享锁和意向排它锁,只要搞清楚一点,这两个锁瞬间就懂了,这一点就是:标准锁和排他锁不可以同时添加!简单说就是,当多个事务都进行了共享锁请求,系统会查看每一个事务请求共享锁的数据是不是已经有了排他锁,如果有,就不再添加共享锁了。如果没有,注意是事务中请求的表中的所有数据都没有添加排他锁,就会被标记,这个标记就叫做意向共享锁,实际执行的时候这些被标记的意向共享锁就会转化为共享锁。

演示:事务A为ID为101的数据添加了排他锁(注意执行的内容是选中内容,没有执行COMMIT!)

BEGIN;
SELECT salary FROM employees WHERE emp_no = 101 FOR UPDATE;
COMMIT;

在这里插入图片描述

事务B为id为101和102的数据请求共享锁,因为事务A中已经为101请求了排它锁,所以事务B中的共享锁请求失败,被阻塞,需要等待事务A提交之后才会执行。

BEGIN;
SELECT salary FROM employees WHERE emp_no = 101 or emp_no = 102 LOCK IN SHARE MODE;
COMMIT;

在这里插入图片描述

事务A提交之后,事务B的数据才会被查询出来,按理说如果添加了共享锁,是可以直接查询出结果的:

在这里插入图片描述

自增锁:就是mysql中的自增,表中如果id字段是自增字段,为了保证其自增id的连续性,其中一个事务插入数据的时候,另一个事务插入数据需要等待前一个事务提交完成才可以继续。这个没什么好演示的。

行锁

记录锁:和排它锁类似,锁会加载包含索引的数据行中,简单说就是通过索引来记录的排它锁,通过索引的辅助,可以避免添加锁需要扫描全表。

演示,注意记录锁需要索引,例子中的mytable表中的id为自增主键,即为索引:

CREATE TABLE mytable (
  id INT AUTO_INCREMENT PRIMARY KEY,
  value VARCHAR(20)
);

INSERT INTO mytable (value) VALUES ('A');
INSERT INTO mytable (value) VALUES ('B');
INSERT INTO mytable (value) VALUES ('C');

事务A执行了查询id=1的数据,value=A,此时没有commit;事务没有提交。

在这里插入图片描述

事务B对id=1的value进行更新操作,把原来的值’A’更新为’X’,执行并commit提交

在这里插入图片描述

此时由于事务A拿着记录锁,事务B更新操作被阻塞,所以数据库中的数据依然是’A’

在这里插入图片描述

提交事务A

在这里插入图片描述

因为事务A已经提交,记录锁被释放,数据库中的数据被更新了。

在这里插入图片描述

间隙锁

主要目的是同一个事务中同样的查询不能有不同的结果:

演示:事务A查询id小于5的数据,其实数据库中只有三条数据

在这里插入图片描述

事务B插入第四条数据,但事务A已经占有了间隙锁,事务B执行被阻塞。如果此时不阻塞,则事务A如果多次相同查询会造成幻读。

在这里插入图片描述

所以我们会看到,数据库依然只有三条数据:

在这里插入图片描述

事务A提交,释放间隙锁

在这里插入图片描述

数据库数据更新为4条

在这里插入图片描述

临键锁

记录锁是为了保持数据一致性,会锁定自身,保证查到的数据在同一个事务里保持一致。间隙锁是为了避免幻读,保证一个事务中多次查询同样的数据结果是一样的,临键锁就是记录锁+间隙锁。

DELETE 流程

在深入分析问题原因之前先对 DELETE 操作的基本流程进行复习。众所周知,MySQL 以页作为数据的基本存储单位,每个页内包含两个主要的链表:正常记录链表和垃圾链表。每条记录都有一个记录头,记录头中包括一个关键属性——deleted_flag。

img

执行 DELETE 操作期间,系统首先将正常记录的记录头中的 delete_flag 标记设置为 1。这一步骤也被称为 delete mark,是数据删除流程的一部分。

img

在事务成功提交之后,由 purge 线程 负责对已标记为删除的数据执行逻辑删除操作。这一过程包括将记录从正常记录链表中移除,并将它们添加到垃圾链表中,以便后续的清理工作。

img

针对不同状态下的记录,MySQL 在加锁时采取不同的策略,特别是在处理唯一索引上记录的加锁情况。以下是具体的加锁规则:

  • 正常记录: 对于未被标记为删除的记录,MySQL 会施加记录锁,以确保事务的隔离性和数据的一致性。
  • delete mark: 当记录已被标记为删除(即 delete_flag 被设置为1),但尚未由 purge 线程清理时,MySQL 会对这些记录施加临键锁,以避免在清理前发生数据冲突。
  • 已删除记录: 对于已经被 purge 线程逻辑删除的记录,MySQL 会施加间隙锁,这允许在已删除记录的索引位置插入新记录,同时保持索引的完整性和顺序性。

原因

在这里插入图片描述

会对这些记录施加临键锁,以避免在清理前发生数据冲突。

  • 已删除记录: 对于已经被 purge 线程逻辑删除的记录,MySQL 会施加间隙锁,这允许在已删除记录的索引位置插入新记录,同时保持索引的完整性和顺序性。

## 原因

最终原作者采用了分布式锁的方案解决了问题,我个人认为是否查看了mysql的锁超时时间呢?是不是锁超时时间设置的太短了呢?

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

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

相关文章

模糊视频一键变清晰,从此告别模糊不清的画质

话不多说,咱们直入主题。你是不是有比较模糊的视频,比如老视频,老电影和监控视频,对了,还有日本土特产(懂的都懂),模糊的视频看起是不是很不舒服,长期久了还会影响视力影…

这些可视化Python库非常强!

介绍的大体流程是:库名、类型、github star、功能、使用方法、案例、学习资料。 第一部分:数据可视化 pyecharts 类型:可视化图表设计 GitHub Star :5985 功能: 简洁的 API 设计,使用如丝滑般流畅&am…

LLM(二):Prompt

一,什么是Prompt 在人工智能领域,Prompt指的是用户给大型语言模型发出的指令。作用是引导模型生成符合预期主题或内容的文本,从而控制生成结果的方向和内容。 大模型是根据用户提出的问题来输出下文,所以用户提出的问题的质量也…

三种智能指针

智能指针 new和delete 1:new初始化 new未初始化值 int *p new int;//p值未定义string *str new string;//为空串&#xff0c;调用string默认构造函数new 初始化值 int *p new int(100);string *str new string(6,a);//aaaaaavector类型指针 vector<int> *p new v…

pikepdf:一个实用的PDF文件处理Python库

我是东哥&#xff0c;今天给大家介绍一个实用的Python库——pikepdf&#xff0c;它能让你像操作文本文件一样轻松地处理PDF&#xff0c;无论是读取、修改还是保存&#xff0c;都能迎刃而解。 基本介绍 pikepdf是一个基于Python的库&#xff0c;它允许开发者轻松地读取、写入和…

第四课,接收键盘输入

一&#xff0c;关于基本框架中头文件的作用 头文件就是一个工具箱&#xff0c;C中有很多工具&#xff0c;我们最熟悉的cout就是其中之一 引入头文件&#xff1a;如果你想在你的代码中使用工具箱里的工具&#xff0c;C会很大方的让你用&#xff0c;但前提是你必须在本页代码的最…

为什么 CNC 加工会产生毛刺?

在现代机械加工领域&#xff0c;CNC(计算机数控)加工以其高精度、高效率的特点被广泛应用。然而&#xff0c;在 CNC 加工过程中&#xff0c;毛刺的产生常常是一个令人困扰的问题。时利和将解析为什么 CNC 加工会产生毛刺呢? 一、刀具磨损 刀具在长时间的使用过程中会逐渐磨损。…

如何一步快速去除黑神话悟空图片上的文字?一招教会你

设计师朋友们&#xff0c;如果老板让你用去除海报上的文字&#xff0c;你会怎么做&#xff1f; 用PS的内容识别填充&#xff0c;图片就会变模糊再精修简直太麻烦啦&#xff01; 还好我最近找到一个图片处理神器&#xff0c;一键就能P去图片的文字&#xff01;简单又高效&…

day04-面向对象-常用API时间Arrays

一、常用API 1.1 StringBuilder类 StringBuilder类代表可变的字符串对象&#xff0c;理解为一个操作字符串的容器相对于String来说,比本来的操作效率更高 ​ StringBuilder常用方法public StringBuilder(): 构建一个空的可变字符串对象public StringBuilder(String str): 构建…

vue3中vite基于vite-plugin-html的多入口打包

先看打包效果 1、安装vite-plugin-html 2、配置多个入口 每个入口都要有模板(index.html、App.vue、main.js复制一份&#xff0c;根据实际需求调整三个文件) 3、配置vite.config.js 4、代码片段 import { createHtmlPlugin } from vite-plugin-htmlconst htmlParams {minif…

关于springboot的Rest请求映射处理的源码分析(一)

我们在开发中很常见的一种方式是通过请求的类型&#xff0c;也就是restful风格来区别我们的请求接口。 通过请求类型的不同(GET POST PUT DELETE) 来区分即便是请求路径相同的请求。 但是他的底层是如何支持的呢&#xff0c;明明我请求路径都是/user。就因为类型不同就能区分到…

网络层 III(划分子网和构造超网)【★★★★★★】

&#xff08;★★&#xff09;代表非常重要的知识点&#xff0c;&#xff08;★&#xff09;代表重要的知识点。 一、网络层转发分组的过程 分组转发都是基于目的主机所在网络的&#xff0c;这是因为互联网上的网络数远小于主机数&#xff0c;这样可以极大地压缩转发表的大小。…

【Python报错】AttributeError`:`‘NoneType‘ object has no attribute ‘XXXX‘`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在Python编程中&#xff0c;AttributeError是一个常见的错误类型&#xff0c;它表示尝试访问的对象没有该属性。本文将探讨…

深度强化学习算法(六)(附带MATLAB程序)

深度强化学习&#xff08;Deep Reinforcement Learning, DRL&#xff09;结合了深度学习和强化学习的优点&#xff0c;能够处理具有高维状态和动作空间的复杂任务。它的核心思想是利用深度神经网络来逼近强化学习中的策略函数和价值函数&#xff0c;从而提高学习能力和决策效率…

CNN网络的一些基本知识

CNN 网络的layer介绍 在卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;中&#xff0c;往往包含许多种不同的网络层交替组成&#xff0c;主要有卷积层&#xff08;Convolutional Layer&#xff09;、池化层&#xff08;Pooling Layer&#…

《黑神话:悟空》爆火,对程序员的 5 点启示(2)

前言 继续上篇未完章节…… 4. 需求捕捉 需求有真需求和伪需求的区别&#xff0c;捕捉和理解用户的真需求对于产品非常重要。 在《黑神话&#xff1a;悟空》面世以后&#xff0c;很多玩家都不吝称赞&#xff0c;有玩家这么评论&#xff1a; 不吹牛逼&#xff0c;这一段我眼…

C#中通过TabControl控制MDI子窗体显示切换的实现过程

类似excel表格中各个表单sheet的切换效果&#xff0c;使用tabcontrol控件实现类似的功能。效果如下&#xff1a; 过程涉及父窗体MDIParent1、子窗体main、自定义基础功能类MdiChildBase。 基础功能类MdiChildBase继承自Form创建&#xff0c;定义了一个委托SetTabControlDelega…

apisix 本地开发环境部署

apisix 本地开发环境部署 本地开发环境部署可以采用 docker-compose 部署&#xff0c;配置文件如下 apisix 配置文件 apisix:node_listen: 9080 # APISIX 节点监听地址enable_ipv6: falsehttp:port: 9080 # APISIX HTTP 端口#https:# port: 9443 # APISIX HTTPS 端口# ssl…

《机器学习》K-means 聚类 原理、参数解析、案例实现

1. 引言 随着数据的快速增长和复杂性的不断提高,如何从大量数据中提取有用信息已成为数据科学和人工智能领域的核心挑战。聚类作为一种无监督学习方法,通过将数据分为若干组,使得同一组内的样本具有较高的相似性,而不同组之间的样本差异显著。这种方法被广泛应用于数据分析…

探索极速Python:Sanic框架的魔力

文章目录 探索极速Python&#xff1a;Sanic框架的魔力背景&#xff1a;为什么选择Sanic&#xff1f;Sanic是什么&#xff1f;如何安装Sanic&#xff1f;简单的库函数使用方法场景应用示例常见Bug及解决方案总结 探索极速Python&#xff1a;Sanic框架的魔力 背景&#xff1a;为什…