前言
死锁日志解读
死锁日志分析
开启mysql锁监控
◆ 前言
本文需要mysql锁的知识,可以看这篇文章:要让初学者都能懂的mysql锁讲解
show engine innodb status;
复制
◆ 死锁日志解读
LATEST DETECTED DEADLOCK
------------------------
2021-11-19 16:50:10 0x7f55c0343700
*** (1) TRANSACTION:
TRANSACTION 68912, ACTIVE 10 sec inserting
mysql tables in use 12, locked 12
LOCK WAIT 8466 lock struct(s), heap size 811216, 152144 row lock(s), undo log entries 1
MySQL thread id 76893, OS thread handle 140005772797696, query id 1446455 127.0.0.1 root Sending data
// 这里把表名隐藏了
INSERT INTO XXX (in_out,
organ_id,
area_id,
vehicle_id,
list_number,
license_plate,
vehicle_number,
list_type_id,
weight_type,
flow_type_id,
supplier_id,
specification_id,
geometry_id,
gross_weight,
tare,
buckle_percent,
buckle_weight,
net_weight,
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 181 page no 16781 n bits 304 index list_number of table `szjz_pro`.`material_weight` trx id 68912 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 197 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 23; hex e694b63230323131303237313433363034333933373039; asc 20211027143604393709;;
1: len 8; hex 800000000007cfb9; asc ;;
*** (2) TRANSACTION:
TRANSACTION 68913, ACTIVE 9 sec setting auto-inc lock
mysql tables in use 12, locked 12
8464 lock struct(s), heap size 811216, 152143 row lock(s)
MySQL thread id 76909, OS thread handle 140006273595136, query id 1446519 119.3.185.17 root Sending data
// 这里把表名隐藏了
INSERT INTO XXX (in_out,
organ_id,
area_id,
vehicle_id,
list_number,
license_plate,
vehicle_number,
list_type_id,
weight_type,
flow_type_id,
supplier_id,
specification_id,
geometry_id,
gross_weight,
tare,
buckle_percent,
buckle_weight,
net_weight,
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 181 page no 16781 n bits 304 index list_number of table `szjz_pro`.`material_weight` trx id 68913 lock mode S locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 23; hex e694b63230323131303236313931393333353336383030; asc 20211026191933536800;;
1: len 8; hex 800000000007cc16; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
TABLE LOCK table `szjz_pro`.`表名` trx id 68913 lock mode AUTO-INC waiting
*** WE ROLL BACK TRANSACTION (2)
复制
starting index read 表示事务状态为根据索引读取数据
fetching rows 表示事务状态在row_search_for_mysql中被设置,表示正在查找记录。
updating or deleting 表示事务已经真正进入了Update/delete的函数逻辑(row_update_for_mysql)
thread declared inside InnoDB 说明事务已经进入innodb层。通常而言 不在innodb层的事务大部分是会被回滚的。
mysql tables in use 12, locked 12 :说明当前的事务使用12个表。locked 12 表示有12个表锁,对于DML语句为LOCK_IX
LOCK WAIT 8466 lock struct(s), heap size 811216, 152144 row lock(s), undo log entries 1 : LOCK WAIT表示正在等待锁, 8466 lock struct(s) 表示trx->trx_locks锁链表的长度为8466,每个链表节点代表该事务持有的一个锁结构。
152144 row lock(s): 表示当前事务持有的锁的个数
下面这是事务正在等待所锁的sql语句,可惜不会显示完整的
INSERT INTO XXX (in_out,
organ_id,
area_id,
vehicle_id,
list_number,
license_plate,
vehicle_number,
list_type_id,
weight_type,
flow_type_id,
supplier_id,
specification_id,
geometry_id,
gross_weight,
tare,
buckle_percent,
buckle_weight,
net_weight,
复制
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 181 page no 16781 n bits 304 index list_number of table `szjz_pro`.`表名` trx id 68912 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 197 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 23; hex e694b63230323131303237313433363034333933373039; asc 20211027143604393709;;
1: len 8; hex 800000000007cfb9; asc ;;
复制
locks gap before rec 表示为gap锁
locks rec but not gap 表示为记录锁
insert intention 表示为插入意向锁
waiting 表示锁等待
*** (2) TRANSACTION:
TRANSACTION 68913, ACTIVE 9 sec setting auto-inc lock
mysql tables in use 12, locked 12
复制
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 181 page no 16781 n bits 304 index list_number of table `szjz_pro`.`表名` trx id 68913 lock mode S locks gap before rec
复制
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
TABLE LOCK table `szjz_pro`.`material_weight` trx id 68913 lock mode AUTO-INC waiting
*** WE ROLL BACK TRANSACTION (2)
复制
◆ 死锁日志分析
但是事务2是insert啊,怎么会有间隙锁?
mysql官网说:
这是官网的文档:https://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html
insert操作是排他记录锁,没有间隙锁,插入前需要加插入意向锁。
但是 INSERT当发生重复键错误时,将在要更新的行上放置排他锁而不是共享锁。对重复的主键值采用独占索引记录锁。对重复的唯一键值采用独占的 next-key 锁。
list_number 就是设置的唯一索引。
认为可能是list_number这个唯一索引的值冲突了。因为代码不是我写的,我也没找到代码,所以找不到具体原因。
还有就是自增锁的问题:他需要锁表,但是其他的表锁还没释放,应该是事务1把这张表锁住了。
以下是死锁问题的原因猜想图:
◆ 开启mysql锁监控
或者使用命令 set global innodb_print_all_deadlocks=on
监控锁信息:
开启锁监控方式:
set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON; // 开启锁监视
set GLOBAL innodb_status_output_locks=OFF; // 关闭锁监视
注:前提需要开启 innodb_status_output
可以查看mysql官网文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-enabling-monitors.html