14.7.5.1 InnoDB 死锁示例
以下示例说明了锁定请求将导致死锁时如何发生错误。该示例涉及两个 Client 端 A 和 B。
首先,Client 端 A 创建一个包含一行的 table,然后开始事务。在事务内,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 |
+------+
接下来,Client 端 B 开始事务并尝试从 table 中删除该行:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM t WHERE i = 1;
删除操作需要X
锁。无法授予该锁,因为它与 Client 端 A 持有的S
锁不兼容,因此该请求进入针对行和 Client 端 B 块的锁请求队列中。
最后,Client 端 A 还尝试从 table 中删除该行:
mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
由于 Client 端 A 需要X
锁才能删除行,因此在此处发生死锁。但是,不能授予该锁定请求,因为 Client 端 B 已经具有X
锁定的请求,并且正在 awaitClient 端 A 释放其S
锁定。由于 B 事先要求X
锁,因此 A 持有的S
锁也不能升级为X
锁。结果,InnoDB
为其中一个 Client 端生成错误并释放其锁。Client 端返回此错误:
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
届时,可以授予对另一个 Client 端的锁定请求,并从 table 中删除该行。