












执行以下命令:
show engine innodb status;
......
------------------------
LATEST DETECTED DEADLOCK
------------------------
2023-03-20 15:26:35 7f37cf7bc700
*** (1) TRANSACTION:
TRANSACTION 2392496607, ACTIVE 0.516 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 35 lock struct(s), heap size 6544, 19 row lock(s), undo log entries 12
LOCK BLOCKING MySQL thread id: 2150145 block 2145491
MySQL thread id 2145491, OS thread handle 0x7f37cc6b3700, query id 25419661194 192.168.1.239 dbuser0026 statistics
select 1 from accdata where tid = 627899 and cmpid =1 and accid = 2 limit 1 for update
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 35006 page no 3012 n bits 360 index `PRIMARY` of table `userdb0026`.`accdata` trx id 2392496607 lock_mode X locks rec but not gap waiting
Record lock, heap no 266 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 00000002; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a0993; asc \ wJ ;;
5: len 8; hex 8000005306ec1f72; asc S r;;
6: len 11; hex 7ffffffffffff83779e08d; asc 7y ;;
*** (2) TRANSACTION:
TRANSACTION 2392496387, ACTIVE 1.529 sec starting index read
mysql tables in use 1, locked 1
45 lock struct(s), heap size 6544, 28 row lock(s), undo log entries 22
MySQL thread id 2150145, OS thread handle 0x7f37cf7bc700, query id 25419661218 192.168.1.239 dbuser0026 updating
update customer set lastdate = case when lastdate < 1679241600 then 1679241600 else lastdate end where tid = 627899 and custid = 3
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 35006 page no 3012 n bits 360 index `PRIMARY` of table `userdb0026`.`accdata` trx id 2392496387 lock_mode X locks rec but not gap
Record lock, heap no 226 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 000003ea; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a09fb; asc \ wJ ;;
5: len 8; hex 8000000000000000; asc ;;
6: len 11; hex 8000000000004d4a691900; asc MJi ;;
Record lock, heap no 266 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 00000002; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a0993; asc \ wJ ;;
5: len 8; hex 8000005306ec1f72; asc S r;;
6: len 11; hex 7ffffffffffff83779e08d; asc 7y ;;
Record lock, heap no 275 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 0000000b; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a0aa1; asc \ wJ ;;
5: len 8; hex 8000000000000000; asc ;;
6: len 11; hex 800000000000a348cd1518; asc H ;;
Record lock, heap no 280 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 00000010; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a09c7; asc \ wJ ;;
5: len 8; hex 8000000000000000; asc ;;
6: len 11; hex 8000000000004aa4750640; asc J u @;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 35097 page no 336 n bits 128 index `PRIMARY` of table `userdb0026`.`customer` trx id 2392496387 lock_mode X locks rec but not gap waiting
Record lock, heap no 45 PHYSICAL RECORD: n_fields 44; compact format; info bits 0
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000003; asc ;;
2: len 6; hex 00008e74b3be; asc t ;;
3: len 7; hex 240000801c2230; asc $ "0;;
4: len 7; hex 43303030393939; asc C000999;;
5: len 12; hex e99bb6e594aee5aea2e688b7; asc ;;
6: len 4; hex 4c534b48; asc LSKH;;
7: len 4; hex 00000002; asc ;;
8: len 1; hex 01; asc ;;
9: len 8; hex 8000000000000000; asc ;;
10: len 8; hex 8000000000010000; asc ;;
......
重点在 LATEST DETECTED DEADLOCK 区域。
LOCK BLOCKING MySQL thread id: 2150145 block 2145491 表示线程 2150145 与线程 2145491 形成死锁。这里可以同时看到两个线程当前加锁的SQL语句:
线程 2145491:
select 1 from accdata where tid = 627899 and cmpid =1 and accid = 2 limit 1 for update
等待 X 锁 (排他锁,但不是间隙锁)于表 accdata 的主键。
RECORD LOCKS space id 35006 page no 3012 n bits 360 index `PRIMARY` of table `userdb0026`.`accdata` trx id 2392496607 lock_mode X locks rec but not gap waiting
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 00000002; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a0993; asc \ wJ ;;
5: len 8; hex 8000005306ec1f72; asc S r;;
6: len 11; hex 7ffffffffffff83779e08d; asc 7y ;;
线程 2150145:
update customer set lastdate = case when lastdate < 1679241600 then 1679241600 else lastdate end where tid = 627899 and custid = 3
已经加了 X 锁 (排他锁,但不是间隙锁)于表 accdata 的主键。
RECORD LOCKS space id 35006 page no 3012 n bits 360 index `PRIMARY` of table `userdb0026`.`accdata` trx id 2392496387 lock_mode X locks rec but not gap
0: len 4; hex 000994bb; asc ;;
1: len 4; hex 00000001; asc ;;
2: len 4; hex 000003ea; asc ;;
3: len 6; hex 00008e9a9903; asc ;;
4: len 7; hex 5c0000774a09fb; asc \ wJ ;;
5: len 8; hex 8000000000000000; asc ;;
6: len 11; hex 8000000000004d4a691900; asc MJi ;;
等待 X 锁 (排他锁,但不是间隙锁)于表 customer 的主键。
RECORD LOCKS space id 35097 page no 336 n bits 128 index `PRIMARY` of table `userdb0026`.`customer` trx id 2392496387 lock_mode X locks rec but not gap waiting
可以看出,2145491 需要锁的表 accdata 的记录区域 0: len 4; hex 000994bb; asc ;; 已被 线程 2150145 锁定,且 线程 2150145 正等待锁另一张表 customer。
尽可能的使用 where 条件减少锁的范围。包括将 join 表中的条件在可能的情况下添加到 where 中。
索引优化,尽量避免重复,避免在遍历索引的时候加上行级锁。
锁可以分为:表锁、页锁、行锁
| 兼容性 | X | S |
|---|---|---|
| X | 不兼容 | 不兼容 |
| S | 不兼容 | 兼容 |
Record Lock (记录锁)
锁直接加在索引记录上,而不是行数据
Gap Lock(间隙锁)
这里需要明白的是,锁加在了索引记录间隙(记住是间隙不是记录本身!),确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别
Next-Key Lock
行锁和间隙锁组合起来就叫 Next-Key Lock,以此防止幻读的发生
默认情况下,InnoDB 中,更新非唯一索引对应的记录,会加上 Next-Key Lock。如果更新记录为空,就不能加记录锁,只能加间隙锁
update / delete 长时间持有锁的 SQL 在事务前面select … for update 语句,如果是在事务里(运行了 start transaction 或设置了 autocommit 等于0),那么就会锁定所查找到的记录select … where … order by rand(); 这样的语句,由于类似这样的语句用不到索引,因此将导致整个表的数据都被锁住此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。