Mysql死锁问题Deadlock found when trying to get lock;try restarting transaction

文章讲述了在测试环境中进行压测时遇到的MySQL死锁问题,涉及到两个事务因互相等待对方持有的排他锁导致的僵局。作者通过查看日志和代码分析,提出增加分布式锁来解决并发操作中的死锁问题。

一、问题描述

今天测试在测试环境做压测,发现了一个报错,来找我帮忙看,如下图:

image-20240108105701985

二、问题排查

先去服务器上,看看死锁的日志,找到 mysql 的安装路径,使用如下命令登录 mysql

mysql -h 数据库IP地址 -P 数据库端口 -u 用户名 -p 库名

输入后,让你输入密码,输入密码之后,就登录成功了,然后再输入如下命令:

SHOW ENGINE INNODB STATUS \G

image-20240108111042370

然后从中找到 LATEST DETECTED DEADLOCK 下面的内容,如下:


LATEST DETECTED DEADLOCK

2024-01-05 21:19:23 0x7f8269fed700
*** (1) TRANSACTION:
TRANSACTION 258666849, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 79628, OS thread handle 140195458455296, query id 9705658 10.100.0.95 root updating
update inc_t_store_return_merchandise_relation SET return_code=‘683901058240105_5’,

merchandise_code=‘60500085’,
apply_return_quantity=1,

returned_quantity=1,
return_unit_code=‘EA’,
returned_unit_code=‘EA’,
make_date=‘2024-01-01 08:00:00’,
batch_code=‘11’,

responsible_party=‘1’,
supplier_code=‘000159’,

price=600.00,

update_id=‘admin’,
update_time=‘2024-01-05 21:18:59.262’ where id=6701831480323817561 AND del_flag=‘N’

*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 9159 page no 31 n bits 128 index PRIMARY of table ■■■■■.inc_t_store_return_order trx id 258666849 lock_mode X locks rec but not gap
Record lock, heap no 61 PHYSICAL RECORD: n_fields 27; compact format; info bits 0
0: len 8; hex 5d01b039393b4058; asc ] 99;@X;;
1: len 6; hex 00000f6af161; asc j a;;
2: len 7; hex 010000091f298d; asc ) ;;
3: len 17; hex 3638333930313035383234303130355f35; asc 683901058240105_5;;
4: len 3; hex 8fd025; asc %;;
5: len 1; hex 31; asc 1;;
6: len 7; hex 3130322d323036; asc 102-206;;
7: len 6; hex 303030313539; asc 000159;;
8: len 1; hex 31; asc 1;;
9: len 11; hex 315f363833393031303538; asc 1_683901058;;
10: SQL NULL;
11: SQL NULL;
12: len 1; hex 31; asc 1;;
13: len 4; hex e9998831; asc 1;;
14: len 2; hex 3320; asc 3 ;;
15: SQL NULL;
16: len 6; hex 313030313033; asc 100103;;
17: len 5; hex 99b24b549f; asc KT ;;
18: len 6; hex 313030313033; asc 100103;;
19: len 5; hex 99b24b549f; asc KT ;;
20: len 1; hex 4e; asc N;;
21: SQL NULL;
22: SQL NULL;
23: SQL NULL;
24: SQL NULL;
25: len 20; hex 36383339303130353832303234303130355f4532; asc 68390105820240105_E2;;
26: len 1; hex 32; asc 2;;

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 9158 page no 27 n bits 120 index PRIMARY of table ■■■■■.inc_t_store_return_merchandise_relation trx id 258666849 lock_mode X locks rec but not gap waiting
Record lock, heap no 53 PHYSICAL RECORD: n_fields 31; compact format; info bits 0
0: len 8; hex 5d01b039393b4059; asc ] 99;@Y;;
1: len 6; hex 00000f6af14e; asc j N;;
2: len 7; hex 020000112921bb; asc )! ;;
3: len 17; hex 3638333930313035383234303130355f35; asc 683901058240105_5;;
4: len 11; hex 315f363833393031303538; asc 1_683901058;;
5: len 8; hex 3630353030303835; asc 60500085;;
6: len 6; hex 800000010000; asc ;;
7: len 6; hex 800000010000; asc ;;
8: len 2; hex 4541; asc EA;;
9: len 3; hex 8fd021; asc !;;
10: len 2; hex 3131; asc 11;;
11: len 4; hex 80000001; asc ;;
12: len 1; hex 33; asc 3;;
13: SQL NULL;
14: SQL NULL;
15: len 6; hex 313030313033; asc 100103;;
16: len 5; hex 99b24b549f; asc KT ;;
17: len 5; hex 61646d696e; asc admin;;
18: len 5; hex 99b24b54bb; asc KT ;;
19: len 1; hex 4e; asc N;;
20: len 6; hex 303030313539; asc 000159;;
21: len 1; hex 31; asc 1;;
22: len 6; hex 303030313539; asc 000159;;
23: SQL NULL;
24: len 9; hex 800000000000025800; asc X ;;
25: len 9; hex 800000000000025800; asc X ;;
26: SQL NULL;
27: SQL NULL;
28: len 2; hex 4541; asc EA;;
29: len 9; hex 800000000000025800; asc X ;;
30: len 9; hex 800000000000000000; asc ;;

*** (2) TRANSACTION:
TRANSACTION 258666830, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 8 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 4
MySQL thread id 79129, OS thread handle 140195152140032, query id 9705666 10.100.0.95 root updating
UPDATE inc_t_store_return_order SET return_code=‘683901058240105_5’, return_date=‘2024-01-05 00:00:00’, return_type=‘2’, dc_code=‘102-206’, supply_institution_code=‘000159’, supply_delivery_type=‘1’, store_code=‘1_683901058’, confirm_user=‘admin’, confirm_time=‘2024-01-05 21:18:59.168’, check_flag=‘1’, status=‘5’, purchase_code=‘68390105820240105_E2’, return_way=‘2’, create_id=‘100103’, create_time=‘2024-01-05 21:18:31’, update_id=‘100103’, update_time=‘2024-01-05 21:18:31’ WHERE id=6701831480323817560 AND del_flag=‘N’

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 9158 page no 27 n bits 120 index PRIMARY of table ■■■■■.inc_t_store_return_merchandise_relation trx id 258666830 lock_mode X locks rec but not gap
Record lock, heap no 53 PHYSICAL RECORD: n_fields 31; compact format; info bits 0
0: len 8; hex 5d01b039393b4059; asc ] 99;@Y;;
1: len 6; hex 00000f6af14e; asc j N;;
2: len 7; hex 020000112921bb; asc )! ;;
3: len 17; hex 3638333930313035383234303130355f35; asc 683901058240105_5;;
4: len 11; hex 315f363833393031303538; asc 1_683901058;;
5: len 8; hex 3630353030303835; asc 60500085;;
6: len 6; hex 800000010000; asc ;;
7: len 6; hex 800000010000; asc ;;
8: len 2; hex 4541; asc EA;;
9: len 3; hex 8fd021; asc !;;
10: len 2; hex 3131; asc 11;;
11: len 4; hex 80000001; asc ;;
12: len 1; hex 33; asc 3;;
13: SQL NULL;
14: SQL NULL;
15: len 6; hex 313030313033; asc 100103;;
16: len 5; hex 99b24b549f; asc KT ;;
17: len 5; hex 61646d696e; asc admin;;
18: len 5; hex 99b24b54bb; asc KT ;;
19: len 1; hex 4e; asc N;;
20: len 6; hex 303030313539; asc 000159;;
21: len 1; hex 31; asc 1;;
22: len 6; hex 303030313539; asc 000159;;
23: SQL NULL;
24: len 9; hex 800000000000025800; asc X ;;
25: len 9; hex 800000000000025800; asc X ;;
26: SQL NULL;
27: SQL NULL;
28: len 2; hex 4541; asc EA;;
29: len 9; hex 800000000000025800; asc X ;;
30: len 9; hex 800000000000000000; asc ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 9159 page no 31 n bits 128 index PRIMARY of table ■■■■■.inc_t_store_return_order trx id 258666830 lock_mode X locks rec but not gap waiting
Record lock, heap no 61 PHYSICAL RECORD: n_fields 27; compact format; info bits 0
0: len 8; hex 5d01b039393b4058; asc ] 99;@X;;
1: len 6; hex 00000f6af161; asc j a;;
2: len 7; hex 010000091f298d; asc ) ;;
3: len 17; hex 3638333930313035383234303130355f35; asc 683901058240105_5;;
4: len 3; hex 8fd025; asc %;;
5: len 1; hex 31; asc 1;;
6: len 7; hex 3130322d323036; asc 102-206;;
7: len 6; hex 303030313539; asc 000159;;
8: len 1; hex 31; asc 1;;
9: len 11; hex 315f363833393031303538; asc 1_683901058;;
10: SQL NULL;
11: SQL NULL;
12: len 1; hex 31; asc 1;;
13: len 4; hex e9998831; asc 1;;
14: len 2; hex 3320; asc 3 ;;
15: SQL NULL;
16: len 6; hex 313030313033; asc 100103;;
17: len 5; hex 99b24b549f; asc KT ;;
18: len 6; hex 313030313033; asc 100103;;
19: len 5; hex 99b24b549f; asc KT ;;
20: len 1; hex 4e; asc N;;
21: SQL NULL;
22: SQL NULL;
23: SQL NULL;
24: SQL NULL;
25: len 20; hex 36383339303130353832303234303130355f4532; asc 68390105820240105_E2;;
26: len 1; hex 32; asc 2;;

*** WE ROLL BACK TRANSACTION (1)

可以看到事务1在根据主键ID更新 inc_t_store_return_merchandise_relation 表,而它持有 inc_t_store_return_order 表的排他锁(lock_mode X),而事务2在根据主键ID更新 inc_t_store_return_order 表,而它持有 inc_t_store_return_merchandise_relation 表的排他锁(lock_mode X),相当于两个事务都在等对方持有的排他锁,于是就死锁了。

去看了下代码,操作步骤如下

1、根据主键ID更新 inc_t_store_return_merchandise_relation

2、根据主键ID更新 inc_t_store_return_order

3、根据主键ID更新 inc_t_store_return_merchandise_relation

三、解决问题

增加分布式锁,让并发不存在

<think>嗯,用户这次提出了MySQL并发Insert操作导致死锁的具体问题,错误信息很明确是"Deadlock found when trying to get lock; try restarting transaction"。从用户引用的资料来看,这个问题MySQL高并发场景下相当常见。 用户引用了5个资料片段,都指向同一个典型现象:并发事务中MySQL检测到死锁后自动回滚。特别是引用[3]展示了实际报错的SQL语句(DELETE操作),引用[5]甚至给出了事务日志片段,说明用户可能已经查看过部分日志。 结合这些引用和我的知识,需要从几个层面考虑解决方案: 首先是索引问题,很多死锁源于缺失必要索引,导致行锁升级为表锁。比如在user_id字段无索引时,即使删除特定user_id的记录,也可能锁定整个表。 其次是事务设计问题,引用[1][2]都暗示事务范围过大容易引发资源竞争。需要检查是否所有操作都需要在同一个事务里,特别是混合insert/update/delete时。 然后是重试机制,引用[2][3]提到这是必要手段,因为MySQL死锁检测机制本身就会要求重试。但要注意退避算法,简单的while循环可能雪上加霜。 最后是隔离级别,引用[4]提到RR隔离级别更容易出现gap锁冲突,而电商场景用RC往往更合适。 用户没有提供具体业务场景,但引用[3]的SQL涉及user_id条件删除,引用[5]是更新return_code字段,推测可能是订单类系统。这类系统尤其要注意热点账户问题,比如集中操作同一商家的退货单。 考虑到用户可能急需解决方案,应该优先给出可立即实施的建议:比如检查索引状态、调整事务范围这些见效快的操作。同时也要提供分析工具的使用方法,毕竟引用[5]显示用户能接触到事务日志,说明有排查权限。 需要提醒的是,死锁在并发场景不可能100%消除,重点在于降低频率和快速恢复。所以重试策略和报警设置也很重要,这在引用[2]的解决方案部分被着重强调过。 </think>以下是针对 MySQL 并发 Insert 操作触发死锁(`Deadlock found when trying to get lock; try restarting transaction`)的综合解决方案,结合引用文献和最佳实践: --- ### **一、根本原因分析** 死锁通常由**事务间循环等待锁资源**引发,常见于以下场景: 1. **索引缺失**:未对 `WHERE` 条件列建立索引,导致行锁升级为表锁(引用[3][4])。 2. **执行顺序不一致**:事务 A 按 `id=1 → id=2` 顺序操作,事务 B 按 `id=2 → id=1` 顺序操作,形成循环等待。 3. **Gap Lock 冲突**:在高并发 `INSERT` 时,事务竞争相邻记录间的间隙锁(Next-Key Lock)(引用[4][5])。 4. **长事务与大事务**:事务包含过多操作,持有锁时间过长(引用[1][3])。 --- ### **二、解决方案** #### 1. **优化索引设计** - **强制使用索引**:为 `WHERE`、`ORDER BY` 涉及的列添加索引,避免全表扫描。 - **减少锁范围**:使用唯一索引或主键插入,缩小间隙锁范围(引用[4])。 ```sql ALTER TABLE `table_name` ADD INDEX `idx_user_id` (`user_id`); -- 引用[3]中缺失索引的案例 ``` #### 2. **调整事务逻辑** - **缩小事务范围**:将大事务拆分为小事务,减少锁持有时间(引用[1][3])。 - **固定操作顺序**:所有事务按相同顺序访问数据(如先操作 `id` 小的记录)。 - **避免热点更新**:如自增主键插入冲突,改用雪花算法等分布式 ID。 #### 3. **降低隔离级别** - 将隔离级别从默认的 `REPEATABLE READ` 改为 `READ COMMITTED`: ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` - **效果**:减少 Gap Lock 的使用(引用[4]),但需评估业务一致性要求。 #### 4. **重试机制** - 捕获死锁异常(错误码 `1213`)后自动重试(引用[2][3]): ```python max_retries = 3 for attempt in range(max_retries): try: execute_insert_transaction() # 执行插入操作 break except MySQLdb.OperationalError as e: if e.args[0] == 1213: # 死锁错误码 sleep(0.1 * (2 ** attempt)) # 指数退避等待 else: raise e ``` #### 5. **监控与日志分析** - **查看死锁日志**:启用 `innodb_print_all_deadlocks`,记录到错误日志(引用[5]): ```sql SET GLOBAL innodb_print_all_deadlocks = ON; ``` - **分析死锁信息**:通过 `SHOW ENGINE INNODB STATUS` 定位冲突事务和 SQL 语句(引用[4][5])。 --- ### **三、预防措施** 1. **避免批量删除后立即插入**:如引用[3]中的 `DELETE ... user_id=?` 语句,在并发下易与插入冲突。 2. **使用乐观锁**:通过版本号控制并发写入,如: ```sql UPDATE table SET col=new_val, version=version+1 WHERE id=1 AND version=old_version; ``` 3. **限制并发线程数**:通过连接池(如 HikariCP)控制数据库访问并发度。 --- ### **死锁分析示例** 引用[5]的事务日志显示: ```log *** (1) TRANSACTION: UPDATE inc_t_store ... SET return_code='683901058240105_5' -- 事务1更新操作 *** (2) TRANSACTION: INSERT INTO inc_t_store ... -- 事务2插入操作 *** (2) HOLDS THE LOCK: RECORD LOCKS ... gap before record -- 持有间隙锁 *** (2) WAITING FOR THIS LOCK: RECORD LOCKS ... insert intention waiting -- 等待插入意向锁 ``` **结论**:事务 1 的更新锁阻塞了事务 2 的插入意向锁,需检查 `return_code` 索引或调整执行顺序[^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步亿点点的小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值