MySQL 8.0 参考手册 / 第 15 章 InnoDB 存储引擎 / 15.7 InnoDB 锁定和事务模型 / 15.7.5 InnoDB 中的死锁 /
14.7.5.1 InnoDB 死锁示例
以下示例说明了当锁定请求导致死锁时错误是如何发生的。该示例涉及两个客户端 A 和 B。
首先,客户端 A 创建一个包含一行的表,然后开始一个事务。在事务中,A 通过
S
在共享模式下选择它来获得对该行的锁定:
mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)
mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
+------+
| i |
+------+
| 1 |
+------+
接下来,客户端 B 开始一个事务并尝试从表中删除该行:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM t WHERE i = 1;
删除操作需要X
锁。锁不能被授予,因为它与
S
客户端 A 持有的锁不兼容,所以请求进入行和客户端 B 块的锁请求队列。
最后,客户端 A 还尝试从表中删除该行:
mysql> DELETE FROM t WHERE i = 1;
X
这里会出现死锁,因为客户端A删除行
需要
锁。但是,无法授予该锁定请求,因为客户端 B 已经有一个X
锁定请求并正在等待客户端 A 释放其S
锁定。也不能
因为 B 事先请求锁而将S
A 持有的锁升级
为锁。结果,
为其中一个客户端生成错误并释放其锁。客户端返回此错误:
X
X
InnoDB
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
此时,可以授予其他客户端的锁定请求,并从表中删除该行。