【mysql】并发 Insert 的死锁问题 第二弹

news2025/12/17 8:57:30

上次死锁的场景还历历在目(【mysql】并发 Insert 的死锁问题:Deadlock found when trying to get lock; try restarting transaction_1213 - deadlock found when trying to get lock; try-CSDN博客),这次又把代码写死了

1. 问题

有 2 张数据库表:

users表: 
    id(主键), name, age, gender, phone, create_t
user_relation表: 
    user_id(外键), relation_id, relation_type
    唯一索引:(user_id, relation_id, relation_type)

在一个事务中,我的 sql 操作为:

-- 插入几条记录到users表
INSERT INTO users (id, name, age, gender, phone, create_t) VALUES
    ('2931502437784617085','user1',20,0,14710002001,'2025-05-15 18:00:00'),
    ('2931502437867716733','user2',20,0,14710002002,'2025-05-15 18:00:00'),
    ('2931502437942362237','user3',20,0,14710002003,'2025-05-15 18:00:00'),
    ...;

-- 删除user_relation表中user_id的所有记录
DELETE FROM user_relation WHERE 
    user_id IN ('2931502437784617085','2931502437867716733','2931502437942362237', ...);

-- 插入几条记录到user_relation表
INSERT INTO user_relation (user_id, relation_id, relation_type) VALUES
    ('2931502437784617085','2931502437814763645','1'),
    ('2931502437867716733','2931502437913198717','1'),
    ('2931502437942362237','2931502438050168957','1'),
    ...;

运行时发现死锁概率极高,甚至并发量不大时(并发为 5,单次 insert 3 条时)还会出现死锁。

mysql 事务隔离级别为:RR

2. 分析死锁日志

SHOW ENGINE INNODB STATUS;

事务 1 持有 X 锁:

RECORD LOCKS space id 971 page no 1672 n bits 464 index userid_relationid_relationtype of table `user_relation_rel` trx id 2339976 lock_mode X locks gap before rec

事务 1 等待某个间隙上的插入意向锁:

RECORD LOCKS space id 971 page no 1672 n bits 440 index userid_relationid_relationtype of table `user_relation_rel` trx id 2339976 lock_mode X locks gap before rec insert intention waiting

事务 2 持有 X 锁:

RECORD LOCKS space id 971 page no 1672 n bits 464 index userid_relationid_relationtype of table `user_relation_rel` trx id 2339977 lock_mode X locks gap before rec

事务 2 等待某个间隙上的插入意向锁:

RECORD LOCKS space id 971 page no 1672 n bits 440 index userid_relationid_relationtype of table `user_relation_rel` trx id 2339977 lock_mode X locks gap before rec insert intention waiting

所以死锁原因为:

表上有唯一索引,在 insert 时会检查唯一性约束,mysql 会先获取间隙锁来防止幻读。当多个事务同时插入时,它们可能在竞争同一个索引页上的间隙锁,互相阻塞形成死锁。

3. 几种解决方法

(1) 调整索引

将 唯一索引  (user_id, relation_id, relation_type) 改为一个普通索引 (user_id)

  • 普通索引没有唯一性约束检查,减少了锁的竞争
  • 锁的范围变小(只会锁定user_id相关范围,而不是三个字段的组合)

结果:死锁情况略有缓解

(2) 修改事务隔离级别

将 RR 改为 RC:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

结果:影响较大,未做修改

(3) 减小每批插入的数据量

结果:单条语句插入个数降到 1 个,只要并发请求还会死锁

(4) 增加重试

在应用代码中判断 mysql 的 error,当死锁时重试几次:

// TxExecWithRetry 执行一个事务函数, 在出现死锁时重试
//
// execFunc: 执行函数
// retryNum: 死锁重试次数
// backOff:  重试间隔(单位ms),按退避策略逐渐递增(50ms、100ms、200ms... 最大maxBackoff)
func TxExecWithRetry(db *database.DB, execFunc func(*sqlx.Tx) error, retryNum, backOff, maxBackoff int) error {
	var err error
	retried := 0

	for retried <= retryNum {
		tx := db.MustBegin()
		err = execFunc(tx)
		if err == nil {
			return tx.Commit()
		} else if !IsDeadlockErr(err) {
			_ = tx.Rollback()
			return err
		}

		slog.Debug("tx exec deadlock, retry...", "retried", retried)
		time.Sleep(time.Duration(backOff+rand.Intn(20)) * time.Millisecond)
		backOff *= 2
		if backOff > maxBackoff {
			backOff = maxBackoff
		}
		retried++
	}
	return err
}

func IsDeadlockErr(err error) bool {
	if err == nil {
		return false
	}
	var mysqlErr *mysql.MySQLError
	if errors.As(err, &mysqlErr) {
		return mysqlErr.Number == 1213
	}
	return false
}

结果:事务执行成功数增加,但是由于重试导致请求时间变长,部分事务甚至需要重试 5 次以上才能成功。

(5) 移去 DELETE 语句(关键!!)

DELETE 操作比 INSERT 操作会锁定更多的行和范围,这才是死锁的根本原因!

DELETE 锁定范围:

  • 记录锁(Record Lock):锁定要删除的每一行数据
  • 间隙锁(Gap Lock):锁定索引记录之间的间隙,防止其他事务插入新记录
  • Next-Key Lock:记录锁+间隙锁的组合,锁定记录及其前面的间隙
  • 二级索引的锁定:还会锁定相关二级索引条目

INSERT 锁定范围:

  • 插入意向锁(Insert Intention Lock):一种特殊的间隙锁,表示打算在某个间隙插入记录
  • 新插入记录上的排他锁:仅锁定新插入的行

所以可以优化 DELETE 语句,按业务需要,可以移去、或软删除、或减小删除范围。

结果:彻底解决

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

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

相关文章

Docker配置SRS服务器 ,ffmpeg使用rtmp协议推流+vlc拉流

目录 演示视频 前期配置 Docker配置 ffmpeg配置 vlc配置 下载并运行 SRS 服务 推拉流流程实现 演示视频 2025-05-18 21-48-01 前期配置 Docker配置 运行 SRS 建议使用 Docker 配置 Docker 请移步&#xff1a; 一篇就够&#xff01;Windows上Docker Desktop安装 汉化完整指…

一个stm32工程从底层上都需要由哪些文件构成

原文链接&#xff1a;https://kashima19960.github.io/2025/05/17/stm32/一个stm32工程从底层上都需要由哪些文件构成/ 前言 我最近因为做课设要用到stm32&#xff0c;所以去找了一些开源的stm32工程来看看&#xff0c;然后发现现在新版的keil mdk对于环境的配置跟以前 相比发…

[Mac] 开发环境部署工具ServBay 1.12.2

[Mac] 开发环境部署工具ServBay 链接&#xff1a;https://pan.xunlei.com/s/VOQS0LDsC_J6XU4p-R6voF6YA1?pwdnbyg# 非常给力的本地 Web 开发/测试环境工具&#xff1a;ServBay。之前我们本地搭个 PHP MySQL Nginx 环境&#xff0c;或者搞个 PHP web 环境啥的&#xff0c;不…

商城小程序源码介绍

今天要为大家介绍一款基于ThinkPHP、FastAdmin以及UniApp开发的商城小程序源码&#xff0c;这款源码在设计和功能上都有不俗的表现&#xff0c;非常适合想要搭建线上商城的开发者。 该源码采用了ThinkPHP作为后端框架&#xff0c;利用其强大的性能和灵活性&#xff0c;保障了系…

科技项目验收测试对软件产品和企业分别有哪些好处?

科技项目验收测试是指在项目的开发周期结束后&#xff0c;针对项目成果进行的一系列验证和确认活动。其目的是确保终交付的产品或系统符合预先设定的需求和标准。验收测试通常包括功能测试、性能测试、安全测试等多个方面&#xff0c;帮助企业评估软件在实际应用中的表现。 科…

汽车零部件冲压车间MES一体机解决方案

在当前制造业升级的大背景下&#xff0c;提升生产效率、实现精细化管理已成为企业竞争力的关键。特别是在汽车零部件制造领域&#xff0c;冲压车间作为生产流程中的重要一环&#xff0c;其生产数据的实时采集与分析对于确保产品质量、优化生产节拍、降低运营成本至关重要。今天…

hysAnalyser 从MPEG-TS导出ES功能说明

摘要 hysAnalyser 是一款特色的 MPEG-TS 数据分析工具。本文主要介绍了 hysAnalyser 从MPEG-TS 中导出选定的 ES 或 PES 功能(版本v1.0.003)&#xff0c;以便用户知悉和掌握这些功能&#xff0c;帮助分析和解决各种遇到ES或PES相关的实际问题。hysAnalyser 支持主流的MP1/MP2/…

家里wifi不能上网或莫名跳转到赌博及色情网站就是域名被劫持、DNS被污染了

文章目录 定义上网过程域名被劫持可能阶段案例排查工具 解决方法清除系统DNS缓存查看DNS缓存清除DNS缓存 登录路由器&#xff0c;设置DNS可用的DNS地址&#xff1a; 找网络运营商报警 定义 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;劫持&#xff0c…

基于SSM实现的健身房系统功能实现十六

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人们健康意识的不断提升&#xff0c;健身行业也在迅速扩展。越来越多的人加入到健身行列&#xff0c;健身房的数量也在不断增加。这种趋势使得健身房的管理变得越来越复杂&#xff0c;传统的手工或部分自动化的管…

【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。 目录 引言设计一个共享数据中心选择数据模型键值对设计 数据可靠性设计持久化快照 &#xff08…

cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx

现象&#xff1a; 上午正常使用cursor/vscode&#xff0c;因为需要写前端安装了nodejs16.20和vue2&#xff0c;结果下午启动前端服务无法访问&#xff0c;浏览器一直转圈。接着测试运行最简单的flask服务&#xff0c;vscode报错connect ETIMEDOUT 127.0.0.1:xx&#xff0c;要么…

兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统

作者&#xff1a;Fei Lin 1 ^{1} 1, Yonglin Tian 2 ^{2} 2, Tengchao Zhang 1 ^{1} 1, Jun Huang 1 ^{1} 1, Sangtian Guan 1 ^{1} 1, and Fei-Yue Wang 2 , 1 ^{2,1} 2,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0c; 2 ^{2} 2中科院自动化研究所…

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤 2025/5/15 19:55 百度&#xff1a;intel 集成显卡 NVIDIA 配置成为 总是用独立显卡 百度为您找到以下结果 ?要将Intel集成显卡和NVIDIA独立显卡配置为总是使用独立显卡&#xff0c;可以通过以下步骤实现?&#xff…

sparkSQL读入csv文件写入mysql

思路 示例 &#xff08;年龄>18改成>20) mysql的字符集问题 把user改成person “让字符集认识中文”

大涡模拟实战:从区域尺度到街区尺度的大气环境模拟

前言&#xff1a; 随着低空经济的蓬勃发展&#xff0c;无人机、空中出租车等新型交通工具正在重塑我们的城市空间。这场静默的革命不仅带来了经济机遇&#xff0c;更对城市大气环境提出了全新挑战。在距离地面200米以下的城市冠层中&#xff0c;建筑物与大气的复杂相互作用、人…

单目测距和双目测距 bev 3D车道线

单目视觉测距原理 单目视觉测距有两种方式。 第一种&#xff0c;是通过深度神经网络来预测深度&#xff0c;这需要大量的训练数据。训练后的单目视觉摄像头可以认识道路上最典型的参与者——人、汽车、卡车、摩托车&#xff0c;或是其他障碍物&#xff08;雪糕桶之类&#xf…

Web开发-JavaEE应用SpringBoot栈SnakeYaml反序列化链JARWAR构建打包

知识点&#xff1a; 1、安全开发-JavaEE-WAR&JAR打包&反编译 2、安全开发-JavaEE-SnakeYaml反序列化&链 一、演示案例-WEB开发-JavaEE-项目-SnakeYaml序列化 常见的创建的序列化和反序列化协议 • &#xff08;已讲&#xff09;JAVA内置的writeObject()/readObje…

项目复习(2)

第四天 高并发优化 前端每隔15秒就发起一次请求&#xff0c;将播放记录写入数据库。 但问题是&#xff0c;提交播放记录的业务太复杂了&#xff0c;其中涉及到大量的数据库操作&#xff1a;在并发较高的情况下&#xff0c;会给数据库带来非常大的压力 使用Redis合并写请求 一…

UE 材质基础 第一天

课程&#xff1a;虚幻引擎【UE5】材质宝典【初学者材质基础入门系列】-北冥没有鱼啊_-稍后再看-哔哩哔哩视频 随便记录一些 黑色是0到负无穷&#xff0c;白色是1到无穷 各向异性 有点类似于高光&#xff0c;可以配合切线来使用&#xff0c;R G B 相当于 X Y Z轴&#xff0c;切…

学习FineBI

FineBI 第一章 FineBI 介绍 1.1. FineBI 概述 FineBI 是帆软软件有限公司推出的一款商业智能 &#xff08;Business Intelligence&#xff09; 产品 。 FineBI 是新一代大数据分析的 BI 工具 &#xff0c; 旨在帮助企业的业务人员充分了解和利用他们的数据 。FineBI 凭借强…