尝试了解InnoDB表上的MySQL死锁

11

我正在尝试理解MySQL在处理相同表的并发客户端时发现的死锁。以下是“SHOW InnoDB STATUS”命令的有趣部分:

------------------------
LATEST DETECTED DEADLOCK
------------------------
120704 16:17:51
*** (1) TRANSACTION:
TRANSACTION 0 3547576, ACTIVE 0 sec, process no 10886, OS thread id 140547111458560 inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 368, 1 row lock(s), undo log entries 1
MySQL thread id 41941, query id 1725666 localhost testsuite update
insert into `INode` (`status`,`_type`,`group`,`ctime`,`parent`,`shared`,`basename`,`_rowid`,`displayname`,`user`,`content_type`,`mtime`,`position`,`atime`,`size`) values ('Published','Group','12','2012-07-04 16:17:48.996869','2',null,'1','12','1','3','application/x-empty','2012-07-04 16:17:48.996896','1','2012-07-04 16:17:48.996914',null)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 5554 n bits 80 index `INodeparent_basename` of table `testsuite`.`INode` trx id 0 3547576 lock mode S waiting
Record lock, heap no 12 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 80000002; asc     ;; 1: len 1; hex 31; asc 1;; 2: len 4; hex 8000000b; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 0 3547575, ACTIVE 0 sec, process no 10886, OS thread id 140547107845888 inserting, thread declared inside InnoDB 493
mysql tables in use 1, locked 1
13 lock struct(s), heap size 3024, 17 row lock(s), undo log entries 21
MySQL thread id 41940, query id 1725808 localhost testsuite update
replace into `INode` (`status`,`_type`,`position`,`group`,`ctime`,`parent`,`basename`,`_rowid`,`displayname`,`user`,`content_type`,`mtime`,`shared`,`atime`,`size`) values ('Published','Group','0','2','2012-07-04 16:17:49','1','groups','2','admin','3','application/x-empty','2012-07-04 16:17:49',null,'2012-07-04 16:17:49',null),('Published','Group','1','11','2012-07-04 16:17:51.064074','2','1','11','1','3','inode/directory','2012-07-04 16:17:51.064074',null,'2012-07-04 16:17:51.064074',null)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 5554 n bits 80 index `INodeparent_basename` of table `testsuite`.`INode` trx id 0 3547575 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;; 1: len 6; hex 67726f757073; asc groups;; 2: len 4; hex 80000002; asc     ;;

Record lock, heap no 12 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 80000002; asc     ;; 1: len 1; hex 31; asc 1;; 2: len 4; hex 8000000b; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 5554 n bits 80 index `INodeparent_basename` of table `testsuite`.`INode` trx id 0 3547575 lock_mode X waiting
Record lock, heap no 12 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 80000002; asc     ;; 1: len 1; hex 31; asc 1;; 2: len 4; hex 8000000b; asc     ;;

*** WE ROLL BACK TRANSACTION (1)
我从这个日志中了解到的是,事务(1)正在等待获取表testsuite的索引INodeparent_basename上的共享锁。现在,事务(2)正在该索引上拥有独占锁。但奇怪的是,事务(2)还在等待给定表上的X锁。如果事务(2)已经拥有该锁,为什么它还要等待呢?
(总的来说,我没有找到任何文件确切地说明如何阅读状态命令的输出 - 如果有人能指出给我,那将很有趣)

你找到答案了吗?我也遇到了同样的问题。 - Andreas Wederbrand
不,我找不到这个问题的答案。在尝试了几个小时后,我只好以不同的方式编写代码,并以程序化的方式串行化数据库访问的一部分,以避免MySQL发现的任何可能的死锁情况。从性能上来看可能会更糟,但我没有其他选择。 - RedGlow
1
关于如何翻译状态命令输出,您(或任何需要帮助的人)可能想要查看我找到的这篇博客:https://www.percona.com/blog/2014/10/28/how-to-deal-with-mysql-deadlocks/ - SourceVisor
2个回答

1
在这种情况下,事务2为先前的语句获取了共享锁。( * (2)持有锁:)

然后,事务1试图在同一行上获取独占锁,并等待共享锁被删除。
然后,事务2在另一个语句中尝试在同一行上获取独占锁。死锁发生了。

不好意思,(2) 已经持有了独占锁。但是 (1) 正在尝试获取共享锁。 - Andreas Wederbrand

-1

我不知道这是否有帮助,但需要考虑引起锁定的操作顺序。在应用程序的一个位置,您创建了如下的锁定:

表1 表2

而在另一个位置则是:

表2 表1(仅为示例)

没有看到实际代码,我建议您查看此类问题,并确保按照相同的工作/更新/插入记录的顺序进行操作,以便它们都像以下方式工作:

从表1插入/更新 然后插入/更新表2

这样,第一次尝试锁定总是在表1上进行...如果无法进行,则在释放表1之前不会尝试表2。

然后,应用对表2的任何更改并完成事务。当表2和表1都被释放时,等待表1释放的下一个事务就可以继续进行了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接