Update 计算机操作系统 - 死锁.md

补充按线程 ID 查询更早执行的语句,附录 A3 补实测输出。
This commit is contained in:
CyC2018
2026-11-04 22:39:58 +08:00
parent ab8da3373c
commit 41665ad273
+22 -1
View File
@@ -262,7 +262,15 @@ INSERT INTO payment VALUES (1025, 50); -- 同样等待事务 1
读 MySQL 8.0 的死锁日志时,两个事务的情况下 (2) 是最后开始等待、使等待关系形成环的事务,(1) 是它在等的事务;(1) HOLDS THE LOCK(S) 列出的就是 (2) 在等的那把锁,反之亦然。
每个事务只显示当时正在执行的语句,持有的锁可能是更早的语句加的,例如附录 A3 中两个事务显示的都是 INSERT,间隙锁却来自之前的 SELECT ... FOR UPDATE。
每个事务只显示当时正在执行的语句,持有的锁可能是更早的语句加的,例如附录 A3 中两个事务显示的都是 INSERT,间隙锁却来自之前的 SELECT ... FOR UPDATE。要找出更早的语句,可以按日志中的 MySQL thread id 查 performance_schema.events_statements_history,它默认为每个连接保留最近 10 条语句(MySQL 8.0 实测,见[附录 A3](#a3-先查后插的间隙锁死锁)):
```sql
SELECT h.EVENT_ID, h.SQL_TEXT
FROM performance_schema.events_statements_history h
JOIN performance_schema.threads t ON t.THREAD_ID = h.THREAD_ID
WHERE t.PROCESSLIST_ID = 4136 -- 死锁日志中的 MySQL thread id
ORDER BY h.EVENT_ID;
```
lock_mode X locks gap before rec 是间隙锁,后面再有 insert intention 的是插入意向锁,在 data_locks 中分别显示为 X,GAP 和 X,GAP,INSERT_INTENTION。
@@ -354,6 +362,19 @@ INSERT INTO payment VALUES (1025, 50)
ERROR 1062 (23000) at line 1: Duplicate entry '1024' for key 'payment.PRIMARY'
```
死锁发生后,按事务 2 的 MySQL thread id 查 events_statements_history(history_size 为 10,这个 consumer 默认开启),能看到它在 INSERT 之前执行的 SELECT ... FOR UPDATE(节选,省略了客户端连接时执行的语句):
```text
*** (2) TRANSACTION:
MySQL thread id 4136, OS thread handle 6157561856, query id 4812446 localhost root update
INSERT INTO payment VALUES (1025, 50)
EVENT_ID SQL_TEXT
3 BEGIN
5 SELECT * FROM payment WHERE order_id = 1025 FOR UPDATE
6 INSERT INTO payment VALUES (1025, 50)
```
执行 SET GLOBAL innodb_print_all_deadlocks = ON 后,再执行一遍可重复读的例子,错误日志中同样记录了两个事务持有的间隙锁和等待的插入意向锁(lock_mode X locks gap before rec insert intention waiting)。
### A4 死锁线程的状态与 CPU 时间