MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction?
在并发场景下sql先删除后批量插入形成死锁
包含共享锁和独占锁
共享锁:简称S锁,当事务读取一条记录时需要先获取修改记录的S锁,如果一条记录持有S锁,其他事务可以继续获取该记录的S锁,但是不能获取X锁。
独占锁:简称X锁,排他锁,如果有一条记录持有X锁,其他事务既不可以获取该记录的S锁,也不能获取该记录的X锁。
一种在记录前面添加的锁,该锁阻止新记录插入到当前记录的前面,直到当前记录的间隙锁释放后,新记录才能正常插入。
相当于RECORD LOCK + GAP LOCK
GAP锁的一种,在执行INSERT前,如果待插入记录的下一条记录被加了GAP锁,则INSERT语句被阻塞,且生成一个插入意向锁。
新插入的记录,不生成锁结构,但由于事务ID的存在,相当于加了隐式锁;别的事务要对这条记录加锁前,先帮助其生成一个锁结构,然后再进入等待状态。
1.当其他事务想获取该记录的S锁或X锁时且该记录所在的聚簇索引中的事务属于活跃状态时,
2.对于insert语句,当遇到唯一二级索引重复时,无论事务处于什么隔离级别都会为记录添加S型锁和Next-key锁,而对于insert...on?duplicate?key这样的语句,当遇到唯一二级索引重复时,无论事务处于什么隔离级别都会为记录添加X型锁和next-key锁
1.查询事务加锁日志
#下面的语句只显示最后一次死锁日志,如果要显示所有发生的死锁日志,需要将系统变量:innodb_print_all_deadlocks设置为ON
SHOW ENGINE INNODB STATUS
2.事务日志分析
------------------------
LATEST DETECTED DEADLOCK
------------------------
2023-12-01 19:09:23 140126396188416
*** (1) TRANSACTION:
TRANSACTION 51320163, ACTIVE 1 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1
MySQL thread id 140744, OS thread handle 140126094022400, query id 4649053 root update
INSERT INTO xxx
*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 8310 page no 46 n bits 624 index express_order_idx of table xxx trx id 51320163 lock_mode X
Record lock, heap no 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 8310 page no 46 n bits 624 index express_order_idx of table xxx trx id 51320163 lock_mode X insert intention waiting
Record lock, heap no 1
*** (2) TRANSACTION:
TRANSACTION 51320168, ACTIVE 1 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1
MySQL thread id 140741, OS thread handle 140130690950912, query id 4649121 root update
INSERT INTO t_express_price
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 8310 page no 46 n bits 624 index express_order_idx of table xxx trx id 51320168 lock_mode X
Record lock, heap no 1
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 8310 page no 46 n bits 624 index express_order_idx of table xxx trx id 51320168 lock_mode X insert intention waiting
Record lock, heap no 1
*** WE ROLL BACK TRANSACTION (2)
RECORD LOCKS...:表示要添加的、处于阻塞中的锁,其中lock_mode X insert intention waiting表示正在等待加X型意向锁
Record lock:表示要加的、处于等待中的锁作用在哪些记录上,可能会有多条。其下方的hex中数据为编码后的数据,如果真实数据为字符串则编码格式为十六进制uft8,如果真实数据为整形则编码格式为十六进制,我们可以将其解码得到真实的数据。
通过解码后的数据我们就能知道锁作用于哪些记录了,这对我们分析死锁是非常有用的。
RECORD LOCKS:表示持有X型排他锁
Record lock:表示持有的锁作用在哪些记录上
通过日志分析发现,TRANSACTION(1)和TRANSACTION(2)都在等待排他插入意向锁(关键字:WAITING FOR THIS LOCK TO BE GRANTED),在这个等待之前TRANSACTION(1)和TRANSACTION(2)持有一个排他记录锁(关键字:HOLDS THE LOCK(S))
日志中没有打印事务1和事务2在等待插入意向锁前获得了什么锁,但是通过代码分析,事务1和事务2也应该是持有了一个排他记录锁(delete语句);
这样双方都在等待对方释放锁,导致了死锁
1.删除时不要通过某个索引进行删除,先获取对应的id,再进行删除
2.修改事务隔离级别
mysql 死锁(先delete 后insert)日志分析_mysql先删再新增死锁-CSDN博客
MySQL 如何避免 RC 隔离级别下的 INSERT 死锁? - 知乎
mysql 并发 删除新增数 锁等待 mysql先删再新增死锁_mob6454cc6c40c9的技术博客_51CTO博客