MySQL数据库发生死锁Deadlock found when trying to get lock; try restarting transaction

本地调试调用接口的发现后台报了Deadlock found when trying to get lock; try restarting transaction这个错误。MySQL数据库发生了死锁。然后使用show engine innodb status 语句,在结果中有一项是LATEST DETECTED DEADLOCK,这里是最近一次的死锁日志。

LATEST DETECTED DEADLOCK

2018-08-29 09:19:31 2b8ec3c81700
*** (1) TRANSACTION:
TRANSACTION 46767594378, ACTIVE 29.727 sec fetching rows
mysql tables in use 3, locked 3
LOCK WAIT 9692 lock struct(s), heap size 1062440, 7 row lock(s), undo log entries 1
LOCK BLOCKING MySQL thread id: 100952799 block 33577558
MySQL thread id 33577558, OS thread handle 0x2b8f0a040700, query id 6019628060 114.55.30.183 safeeduuser Searching rows for update
update tb_result set ResultStatues=1 where StudentId=8768 and ExamId=155 and QuestionId=49011
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594378 lock_mode X locks rec but not gap waiting
Record lock, heap no 575 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802e4c1a; asc  .L ;;

*** (2) TRANSACTION:
TRANSACTION 46767594555, ACTIVE 11.234 sec fetching rows
mysql tables in use 3, locked 3
9177 lock struct(s), heap size 1013288, 4 row lock(s), undo log entries 1
MySQL thread id 100952799, OS thread handle 0x2b8ec3c81700, query id 6019630549 114.55.30.183 safeeduuser Searching rows for update
update tb_result set ResultStatues=1 where StudentId=8768 and ExamId=155 and QuestionId=49077
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594555 lock_mode X locks rec but not gap
Record lock, heap no 575 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802e4c1a; asc  .L ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594555 lock_mode X locks rec but not gap waiting
Record lock, heap no 152 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802a6908; asc  *i ;;

*** WE ROLL BACK TRANSACTION (2)

解释一下日志的大概意思

mysql tables in use 3, locked 3
LOCK WAIT 9692 lock struct(s), heap size 1062440, 7 row lock(s), undo log entries 1
事务一,当前正在操作3张表,持有9692把锁,其中7个行级锁

(1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594378 lock_mode X locks rec but not gap waiting
Record lock, heap no 575 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802e4c1a; asc  .L ;;
行锁处于等待状态
等待的行锁,加锁的对象是索引`idx_student` 页面号为49521上的行,这个行锁一共有1192个bits可以用来锁1192个行记录,行锁模式为next key锁(lock_mode X )next key锁有两层含义,一是对当前记录加X锁,防止记录被并发修改,同时锁住记录之前的GAP,防止有新的记录插入到此记录之前。

*** (2) TRANSACTION:
TRANSACTION 46767594555, ACTIVE 11.234 sec fetching rows
mysql tables in use 3, locked 3
9177 lock struct(s), heap size 1013288, 4 row lock(s), undo log entries 1
事务二,当前正在操作3张表,持有9177锁,把行级锁
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594555 lock_mode X locks rec but not gap
Record lock, heap no 575 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802e4c1a; asc  .L ;;
行锁对应的也是索引`idx_student` 上页面号为49521上的记录,行锁处于持有状态,锁模式为X lock with no gap(注:记录锁,只锁记录,但是不锁记录前的GAP,no gap lock)
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 14116 page no 49521 n bits 1192 index `idx_student` of table `safeedu_db`.`tb_result` trx id 46767594555 lock_mode X locks rec but not gap waiting
Record lock, heap no 152 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80002240; asc   "@;;
 1: len 4; hex 802a6908; asc  *i ;;
行锁处于等待状态,等待记录锁

需要知道的是,在UPDATE、DELETE操作时,MySQL的InnoDB引擎不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking。

总结

事务一是 lock_mode X locks rec but not gap waiting
事务二是 lock_mode X locks rec but not gap,还有一个lock_mode X locks rec but not gap waiting
可以理解成事务一的next key lock X正在等待事务二中持有的X lock with no gap(行锁X冲突),同时事务二的next key lock x却又在等待事务一种正在等待的next key锁,形成循环,死锁产生。

解决

根据业务分析,这里的UPDATE操作可以合并之前的业务代码中,然后就避免发生死锁的情况了。

猜你喜欢

转载自blog.csdn.net/wantaceveryday/article/details/84934786