当前位置: 首页 > news >正文

如何与死锁斗争!!!

其他系列文章导航

Java基础合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、死锁场景现场

二、死锁是如何产生的

三、死锁排查思路

四、sql模拟死锁复现

五、死锁的解决方案


前言

为避免影响业务,应尽可能避免修改线上数据库的字段,因为这可能导致锁表并可能导致死锁。

但是如果数据库确实出现了死锁,就需要采取相应的排查思路来解决问题,以恢复业务的正常运行。

本文将分享一些有关数据库死锁排查的思路和方法,以便在出现问题时能够有足够的把握解决它们。


一、死锁场景现场

模拟场景:对用户数据进行迁移。

把业务礼物表A的数据删除,然后修改用户ID后,然后插入到礼物B表。其中,A表和B表,表示同一个礼物逻辑表下的不同分表

CREATE TABLE `gift` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`sender_id` int DEFAULT NULL COMMENT '赠送者ID',`gift_type` varchar(50) NOT NULL COMMENT '礼物类型',`gift_id` varchar(50) NOT NULL COMMENT '礼物ID',`gift_name` varchar(100) NOT NULL COMMENT '礼物名称',`created_time` datetime DEFAULT NULL COMMENT '创建时间',`updated_time` datetime DEFAULT NULL COMMENT '更新时间',`gift_send_time` datetime DEFAULT NULL COMMENT '礼物赠送时间',`quantity` int DEFAULT NULL COMMENT '礼物数量',`receiver_id` int DEFAULT NULL COMMENT '接收者ID',`message` text COMMENT '消息',`status` varchar(20) DEFAULT NULL COMMENT '状态',`expiry_time` datetime DEFAULT NULL COMMENT '过期时间',`channel_no` varchar(50) DEFAULT NULL COMMENT '渠道',`flow_no` varchar(50) NOT NULL COMMENT '流水号',PRIMARY KEY (`id`),UNIQUE KEY `idx_unique_flow_no` (`flow_no`)
)

在进行礼物流水表数据迁移的过程中,出现了 死锁等待超时 的场景。 

从日志可以看出,是在执行礼物赠送流水表删除的时候,阻塞等待,最后锁等待超时了。出现这种情况,一般都是因为产生了死锁。 

既然是死锁,为什么出现的却是Lock wait timeout exceeded; try restarting transaction 锁等待超时这个日志呢?这是因为在Innodb存储引擎中,当检测到死锁时,它会尝试自动解决死锁问题,通常是通过回滚(rollback)其中的一个或者多个事务来解除死锁。 


二、死锁是如何产生的

死锁产生的条件包括:

  • 互斥条件:至少有一个资源是独占的,即一次只能被一个进程或线程使用。

  • 持有和等待条件:一个进程或线程可以持有一个资源,并等待其他进程或线程持有的资源。

  • 非抢占条件:已经分配给一个进程或线程的资源不能被强制性地抢占,只能由持有资源的进程或线程显式释放。

  • 循环等待条件:一系列进程或线程形成循环等待其他进程或线程持有的资源。


三、死锁排查思路

死锁的排查思路:

  1. show engine innodb status,查看最近一次死锁日志。

  2. 分析死锁日志,找到关键词TRANSACTION。

  3. 分析死锁日志,查看正在执行的SQL。

  4. 看它持有什么锁,等待什么锁。

顺着这个排查思路,我们先复现这个死锁案例。在删除礼物赠送流水表阻塞等待的过程,执行show engine innodb status命令,查看事务和锁的信息。

通过日志,看到这个事务正在执行的SQL是:

DELETE FROM gift_send_flow_0 WHERE flow_no = 'flowNo666' AND sender_id = 10000

它在等待一个idx_unique_flow_no的排他行锁。那么到底是什么SQL持有了这个锁,导致它阻塞等待呢,这时候,我们联系上下文代码,把操作这个表相关的插入或者修改、删除的SQL都梳理一下,最后发现是一条插入的SQL涉及到: 

 <insert id="insertGiftSendFlow" parameterType="com.example.demo.generate.GiftSendFlowTab">INSERT INTO gift_send_flow (id,gift_type, gift_id, gift_name, created_time, updated_time,gift_send_time, quantity, sender_id, receiver_id, message, status, expiry_time, channel_no,flow_no)VALUES (#{id},#{giftType}, #{giftId}, #{giftName}, #{createdTime}, #{updatedTime},#{giftSendTime}, #{quantity}, #{senderId}, #{receiverId}, #{message}, #{status}, #{expiryTime}, #{channelNo},#{flowNo})</insert>

 我们迁移的过程,涉及把原来记录删除掉,然后替换senderId,再执行插入。基本确定就是删除和插入的SQL形成的死锁。我们再来本地模拟这两条SQL的并发执行。


四、sql模拟死锁复现

先开启一个事务A,执行删除,插入:

mysql> BEGIN;
Query OK, 0 rows affected (0.01 sec)mysql> DELETE FROM gift_send_flow_0 WHERE flow_no = 'flowNo666' AND sender_id = 10000;
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO gift_send_flow_0 (id,gift_type, gift_id, gift_name, created_time, updated_time, gift_send_time, quantity, sender_id, receiver_id, message, status , expiry_time, channel_no,flow_no) VALUES (null,'虚拟', '1', '玫瑰花', '2023-11-21 22:57:28', '2023-11-21 22:57:28', '2023-11-21 22:57:28', 1,  170000, 10025, '送给女嘉宾', NULL , NULL,'1000','flowNo666');
Query OK, 1 row affected (0.01 sec)

另开一个事务,再执行删除、插入,发现在执行删除的时候,就进入了阻塞等待。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> DELETE FROM gift_send_flow_0 WHERE flow_no = 'flowNo666' AND sender_id = 10000;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

通过show engine innodb status查看死锁日志与上面场景的日志相同。

为了进一步验证,可以通过这个命令(MySQL 8.0+)查看SQL加锁情况:

SELECT * FROM performance_schema.data_locks\G;

会发现INSERT语句的时候,持有了唯一索引的排他行锁,然后DELETE的时候,也需要获取这个锁,因此形成死锁循环等待。 


五、死锁的解决方案

因为并发执行删除和插入同一个表,因此形成死锁

死锁的方案解决方案有:

  • 避免循环等待:保证资源分配的有序性,例如,定义一个全局的资源申请顺序,并要求所有进程按照这个顺序申请资源。这样可以避免循环等待的情况。

  • 资源有序性:按照固定的顺序获取资源,避免多个进程在不同的顺序下请求资源,导致循环等待的情况。

  • 超时机制:当一个进程无法获取所需资源时,设置一个超时机制,超过一定时间后放弃等待的资源并释放自己所持有的资源,避免长时间等待。

回到本文的案例,那就是 迁移数据的时候控制有序性,串行执行就好

相关文章:

如何与死锁斗争!!!

其他系列文章导航 Java基础合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、死锁场景现场 二、死锁是如何产生的 三、死锁排查思路 四、sql模拟死锁复现 五、死锁的解决方案 前言 为避免影响业务&#xff0c;应尽可能避…...

【Java并发】聊聊不安全的HashMap以及ConcurrentHashMap

在实际的开发中&#xff0c;hashmap是比较常用的数据结构&#xff0c;如果所开发的系统并发量不高&#xff0c;那么没有问题&#xff0c;但是一旦系统的并发量增加一倍&#xff0c;那么就可能出现不可控的系统问题&#xff0c;所以在平时的开发中&#xff0c;我们除了需要考虑正…...

数据结构--->单链表

文章目录 链表链表的分类 单链表单链表的存储结构单链表主要实现的接口函数单链表尾插动态申请新节点单链表头插单链表的尾删单链表的头删在指定位置之前插入单链表查找插入 在指定位置之后插删除指定位置元素删除指定位置之后的元素顺序输出链表销毁单链表 顺序表和单链表的区…...

RT-Thread 线程间同步【信号量、互斥量、事件集】

线程间同步 一、信号量1. 创建信号量2. 获取信号量3. 释放信号量4. 删除信号量5. 代码示例 二、互斥量1. 创建互斥量2. 获取互斥量3. 释放互斥量4. 删除互斥量5. 代码示例 三、事件集1. 创建事件集2. 发送事件3. 接收事件4. 删除事件集5. 代码示例 简单来说&#xff0c;同步就是…...

B 树和 B+树 的区别

文章目录 B 树和 B树 的区别 B 树和 B树 的区别 了解二叉树、AVL 树、B 树的概念 B 树和 B树的应用场景 B 树是一种多路平衡查找树&#xff0c;为了更形象的理解。 二叉树&#xff0c;每个节点支持两个分支的树结构&#xff0c;相比于单向链表&#xff0c;多了一个分支。 …...

Go iota简介

当声明枚举类型或定义一组相关常量时&#xff0c;Go语言中的iota关键字可以帮助我们简化代码并自动生成递增的值。本文档将详细介绍iota的用法和行为。 iota关键字 iota是Go语言中的一个预定义标识符&#xff0c;它用于创建自增的无类型整数常量。iota的行为类似于一个计数器…...

PyQt6库和工具库QTDesigner安装与配置

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计12条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…...

性能测试:系统架构性能优化思路

今天谈下业务系统性能问题分析诊断和性能优化方面的内容。这篇文章重点还是谈已经上线的业务系统后续出现性能问题后的问题诊断和优化重点。 系统性能问题分析流程 我们首先来分析下如果一个业务系统上线前没有性能问题&#xff0c;而在上线后出现了比较严重的性能问题&#x…...

python字符串格式化

字符串格式化 # 2023年11月16日 星期四 y 2023 m 11 d 16 w 四 s %d年%d月%d日 星期%s%(y,m,d,w) print(s) s {}年{}月{}日 星期{}.format(y,m,d,w) print(s) s f{y}年{m}月{d}日 星期{w} print(s)...

Linux的基本指令(二)

目录 前言 学前补充 touch指令 mkdir指令 rmdir指令 rm指令 通配符* man指令 cp指令 mv指令(重要) 补充内容&#xff1a; 1、如何快速在Linux中写出代码 2、如何看待如此多的Linux指令 cat指令 前言 关于Linux的基本指令我们会分三到四篇文章进行分析&#xff0c…...

每日一题--寻找重复数

蝶恋花-王国维 阅尽天涯离别苦&#xff0c; 不道归来&#xff0c;零落花如许。 花底相看无一语&#xff0c;绿窗春与天俱莫。 待把相思灯下诉&#xff0c; 一缕新欢&#xff0c;旧恨千千缕。 最是人间留不住&#xff0c;朱颜辞镜花辞树。 目录 题目描述&#xff1a; 思路分析…...

C#,《小白学程序》第二十二课:大数的乘法(BigInteger Multiply)

1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary> /// 大数的&#xff08;加减乘除&#xff09;四则运算、阶乘运算 /// 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法 /// </summary> p…...

kafka,RabbitMQ,RocketMQ,他们之间的区别,架构,如何保证消息的不丢失,保证不重复消费,保证消息的有序性

文章目录 Kafka、RabbitMQ、RocketMQ 之间的区别是什么&#xff1f;性能数据可靠性服务可用性功能 RabbitMQ如何保证消息不丢失&#xff1f;Kafka 的架构说一下&#xff1f;Kafka 怎么保证消息是有序的&#xff1f;Kafka 怎么解决重复消费&#xff1f;Kafka 怎么保证消息不丢失…...

uni-app中vue3+setup实现下拉刷新、上拉加载更多效果

在小程序或各类app中&#xff0c;下拉刷新和上拉加载更多是极为常见和使用非常频繁的两个功能&#xff0c;通过对这两个功能的合理使用可以极大的方便用户进行操作。 合理的设计逻辑才能更容易挽留住用户&#xff0c;因为这些细节性的小功能点就变得极为重要起来。 那么在uni…...

微服务实战系列之Nginx(技巧篇)

前言 今天北京早晨竟然飘了一些“雪花”&#xff0c;定睛一看&#xff0c;似雪非雪&#xff0c;像泡沫球一样&#xff0c;原来那叫“霰”。 自然中&#xff0c;雨雪霜露雾&#xff0c;因为出场太频繁&#xff0c;认识门槛较低&#xff0c;自然不费吹灰之力&#xff0c;即可享受…...

好工具|datamap,一个好用的地图可视化Excel插件,在Excel中实现地理编码、拾取坐标

在做VRP相关研究的时候&#xff0c;需要对地图数据做很多处理&#xff0c;比如地理编码&#xff0c;根据“重庆市沙坪坝区沙正街174号”这样的一个文本地址知道他的经纬度&#xff1b;再比如绘制一些散点图&#xff0c;根据某个位置的经纬度在地图上把它标注出来。还有有的时候…...

Java——继承

继承是面向对象编程的三大特征之一&#xff0c;它让我们更加容易实现对已有类的扩展、更加容易实现对现实世界的建模。 继承有两个主要作用&#xff1a; 代码复用&#xff0c;更加容易实现类的扩展方便建模 继承的实现 继承让我们更加容易实现对类的扩展。比如我们定义了人…...

十、sdl显示yuv图片

前言 SDL中内置加载BMP的API&#xff0c;使用起来会更加简单&#xff0c;便于初学者学习使用SDL 如果需要加载JPG、PNG等其他格式的图片&#xff0c;可以使用第三方库&#xff1a;SDL_image 测试环境&#xff1a; ffmpeg的4.3.2自行编译版本windows环境qt5.12sdl2.0.22&…...

Docker Nginx容器部署vue项目

Docker Nginx容器部署vue项目 文章目录 Docker Nginx容器部署vue项目1. 前提2. 下载nginx镜像3. 编写nginx.conf配置文件4. 编写构建命令5. vue项目上传 1. 前提 Docker服务已部署 2. 下载nginx镜像 首先查看有没有nginx镜像 docker images没有的情况下再进行下载 docker …...

【深度学习】如何找到最优学习率

经过了大量炼丹的同学都知道&#xff0c;超参数是一个非常玄乎的东西&#xff0c;比如batch size&#xff0c;学习率等&#xff0c;这些东西的设定并没有什么规律和原因&#xff0c;论文中设定的超参数一般都是靠经验决定的。但是超参数往往又特别重要&#xff0c;比如学习率&a…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...