【问题标题】:Deadlock issue when transaction tries to accuire a lock it's already holding当事务试图获取它已经持有的锁时出现死锁问题
【发布时间】:2013-03-14 15:04:12
【问题描述】:

我发现了一个非常令人困惑的死锁情况,需要帮助才能理解。

有两个交易正在进行:
(2) 持有查询delete from myTable where id = NAME_CONST('p_id',10000) 的锁。这是 PRIMARY KEY 的锁,虽然不是完整的密钥,而是一个范围。当它说lock_mode X locks rec but not gap时,这对我来说似乎是一个完整的写锁。
(1) 正在等待同一个锁,也等待查询delete from myTable where id = NAME_CONST('p_id',10000)
(2) 也在尝试获取这个锁,MySQL 检测到死锁。

我无法理解的是为什么 (2) 必须再次获取锁,因为它已经持有它并且在所有情况下它都是一个写锁 (lock_mode X)。

它看起来也适用于完全相同的查询。

这是表定义

create myTable (
  id int unsigned not null,
  value1 char(8) not null,
  value2 int unsigned,
  primary key (id, value1)
);

这是来自SHOW ENGINE INNODB STATUS\G的信息

------------------------
LATEST DETECTED DEADLOCK
------------------------
130313 14:46:28
*** (1) TRANSACTION:
TRANSACTION 75ACB8A3, ACTIVE 0 sec, process no 6110, OS thread id 139973945382656 starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 5154970, query id 5201313618 192.168.0.2 user updating
delete from myTable where id = NAME_CONST('p_id',10000)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 22371 page no 1598 n bits 104 index `PRIMARY` of table `db`.`myTable` trx id 75ACB8A3 lock_mode X waiting
Record lock, heap no 32 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 0005af3a; asc :;;
1: len 8; hex 2020202020202020; asc ;;
2: len 6; hex 000075acb890; asc u ;;
3: len 7; hex ea0000020d011e; asc ;;
4: len 4; hex 00000065; asc e;;

*** (2) TRANSACTION:
TRANSACTION 75ACB890, ACTIVE 0 sec, process no 6110, OS thread id 139973957895936 starting index read
mysql tables in use 1, locked 1
7 lock struct(s), hea
p size 1248, 6 row lock(s), undo log entries 4
MySQL thread id 5155967, query id 5201313625 192.168.0.1 user updating
delete from myTable where id = NAME_CONST('p_id',10000)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 22371 page no 1598 n bits 104 index `PRIMARY` of table `db`.`myTable` trx id 75ACB890 lock_mode X locks rec but not gap
Record lock, heap no 32 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 0005af3a; asc :;;
1: len 8; hex 2020202020202020; asc ;;
2: len 6; hex 000075acb890; asc u ;;
3: len 7; hex ea0000020d011e; asc ;;
4: len 4; hex 00000065; asc e;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 22371 page no 1598 n bits 104 index `PRIMARY` of table `db`.`myTable` trx id 75ACB890 lock_mode X waiting
Record lock, heap no 32 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 0005af3a; asc :;;
1: len 8; hex 2020202020202020; asc ;;
2: len 6; hex 000075acb890; asc u ;;
3: len 7; hex ea0000020d011e; asc ;;
4: len 4; hex 00000065; asc e;;

*** WE ROLL BACK TRANSACTION (1)

【问题讨论】:

  • 您是否尝试重现错误?如果“是”,你能告诉我们场景吗?
  • 我已经尝试使用start transaction; delete...; rollback; 从两个模拟线程中尽可能快地执行此删除操作,就像 bash 可以将其提供给 mysql 一样快,但我一次都没有遇到死锁。我完全不知道这是怎么发生的。
  • 请参阅这个问题(它描述了如何捕获死锁):stackoverflow.com/questions/2143873/…。还有一篇关于检测和恢复死锁的好文章:dwachira.hubpages.com/hub/…。一般来说,死锁是架构和设计的问题。您应该检查更新数据的流程。
  • 也许我不够清楚。我已经对死锁了解很多。它们是什么,它们如何出现以及如何防止它们。这次我的问题是我不明白为什么事务 (2) 需要获取它已经持有的锁。这可能更多的是关于 innoDB 的问题,而不是一般的死锁。
  • 生产数据库上show variables like '%autocommit%'的结果是什么?

标签: mysql transactions innodb deadlock


【解决方案1】:

这不是同一个锁 - 事务 1 具有的锁仅在(索引)记录上,而不是间隙锁。

这是发生了什么:

  1. 事务 2 获得了(索引)记录的锁而不是记录之前的间隙('rec but not gap'),即它只有一个记录锁。
  2. 事务 1 尝试获取记录上的锁和之前的间隙(即下一个键锁),但不能因为事务 2 有记录锁(因此事务 1 等待)。
  3. 事务 2 尝试获取记录上的锁和之前的间隙(即下一个键锁)但不能,因为事务 1 已经在等待同一个锁并且领先于它在队列中。
  4. 死锁。

我不完全确定为什么事务 2 没有立即获取下一个键锁——也许获取记录锁和间隙锁的过程不是原子的(一般意义上的)。

我认为问题在于您有一个复合主键 (id, value1) 但您正在从一个范围中删除(仅指定 id) - 这需要间隙锁。见http://dev.mysql.com/doc/refman/5.0/en/innodb-record-level-locks.html,特别是:

使用唯一值锁定行的语句不需要间隙锁定 索引来搜索唯一的行。 (这不包括 搜索条件仅包括多列中的某些列 唯一索引;在这种情况下,确实会发生间隙锁定。)

您能否更改您的代码,以便在删除时指定完整的主键,即 id value1?

其他选项:

  • 出现死锁时重试删除,例如捕获代码中的错误,如果它是由死锁引起的,请重试。这种方法说起来容易做起来难,尤其是在遗留应用程序中,但how to cope with deadlocks 上的 MySQL 页面推荐:

如果由于以下原因导致交易失败,请随时准备重新发出交易 僵局。死锁并不危险。请再试一次。

  • 在发出删除语句之前用表级锁锁定整个表。不过,这可能会影响性能,是一种“大锤”方法。

【讨论】:

  • 如果我在 IN 语句或连接中添加所有可能键的内部选择,这可能是可能的。感觉很奇怪,单个删除语句应该 a) 不是原子的并且 b) 速度不够快,以至于任何其他删除实际上都被它锁定。
  • 您多久遇到一次这些死锁?删除之前的事务中是否发生了其他任何事情?有多少并发线程正在运行删除?能发一下代码吗?
  • 每天都会发生几次,总是来自两台不同的机器。在与该表相关的删除之前没有发生任何事情。其他事情发生在其他桌子上,但这无关紧要。我无法发布未加密的代码。
  • 没有关于为什么删除语句不立即获取完整锁定的指针?那部分仍然让我感到困惑。
  • 我会奖励赏金指出手册说它可能发生的地方,但不幸的是我仍然不明白为什么会发生这种情况,它违背了我所了解的关于事务和死锁的一切.
猜你喜欢
  • 1970-01-01
  • 2013-09-20
  • 1970-01-01
  • 2013-07-18
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多