首页 > 解决方案 > 为什么会发生mysql死锁?

问题描述

我有一个mysql表:

CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `value` int(10) unsigned NOT NULL,
  `idxvalue` int(10) unsigned NOT NULL,
  `ukvalue` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_value` (`ukvalue`),
  KEY `idx_value` (`idxvalue`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

我在表中插入 2 行:

insert into test (id, value, idxvalue, ukvalue) values (10, 1, 3, 3);
insert into test (id, value, idxvalue, ukvalue) values (20, 1, 3, 4);

然后我创建了一个事务(Transaction1):

> begin;

> insert into test (id, value, idxvalue, ukvalue) values (9, 1, 3, 3);
ERROR 1062 (23000): Duplicate entry '3' for key 'uk_value'

> delete from test where ukvalue = 3;
Query OK, 1 row affected (0.00 sec)

然后我创建了另一个事务(Transaction2):

> insert into test (id, value, idxvalue, ukvalue) values (13, 1, 3, 3);

然后我回到 Transaction1,运行:

> insert into test (id, value, idxvalue, ukvalue) values (14, 1, 3, 3);
Query OK, 1 row affected (0.00 sec)

> delete from test where ukvalue = 3;
Query OK, 1 row affected (0.00 sec)

同时,在 Transaction2 中,我得到:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

为什么这里会发生死锁?谢谢

环境:mysql 5.7.28-0 linux ubuntu0.18.04.4

标签: mysqltransactionslockingdeadlock

解决方案


请检查“SHOW ENGINE INNODB STATUS”以查看有关死锁的详细信息。

当您执行查询“delete from test where ukvalue = 3”时,事务 1 锁定 ukvalue = 3 的索引,锁定模式为“X locks rec but not gap”。

当您执行查询“insert into test (id, value, idxvalue, ukvalue) values (13, 1, 3, 3)”时,事务 2 开始等待以模式 S 获取 ukvalue = 3 的索引锁定。事务 2 是现在等待事务 1 释放 X 锁。

当您在事务 1 中执行其余查询时,事务 1 尝试使用“在 rec 插入意图等待之前锁定间隙”模式为 ukvalue = 3 获取另一个索引锁。事务 1 现在正在等待事务 2 释放 S 锁。

事务 2 现在正在等待事务 1,而事务 1 正在等待事务 2。这是一个死锁。


推荐阅读