1

我从 SHOW ENGINE INNODB STATUS 获得信息

    *** (1) TRANSACTION: 
TRANSACTION 0 2799914, ACTIVE 1 sec, process no 4106, OS thread id 139808903796480 inserting
mysql tables in use 1, locked 1
LOCK WAIT 10 lock struct(s), heap size 1216, 7 row lock(s), undo log entries 3
MySQL thread id 4284, query id 2889649 localhost 127.0.0.1 test update
INSERT INTO shipping .....
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 436366 n bits 88 index `PRIMARY` of table `testdatabase`.`order` trx id 0 2799914 lock mode S locks rec but not gap waiting
Record lock, heap no 14 PHYSICAL RECORD: n_fields 213; compact format; info bits 0
..........;

*** (2) TRANSACTION:
TRANSACTION 0 2799913, ACTIVE 1 sec, process no 4106, OS thread id 139808905824000 starting index read, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1216, 5 row lock(s), undo log entries 4
MySQL thread id 4290, query id 2889711 localhost 127.0.0.1 test Updating
UPDATE order
........
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 436366 n bits 88 index `PRIMARY` of table `testdatabase`.`order` trx id 0 2799913 lock_mode X locks rec but not gap
Record lock, heap no 14 PHYSICAL RECORD: n_fields 213; compact format; info bits 0
..........

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 153737 n bits 88 index `PRIMARY` of table `testdatabase`.`order` trx id 0 2799913 lock_mode X locks rec but not gap waiting
Record lock, heap no 10 PHYSICAL RECORD: n_fields 213; compact format; info bits 0
......

*** WE ROLL BACK TRANSACTION (2)
------------
TRANSACTIONS 

船上有一个 FK 指的是订单主键。

我认为 T2 已经持有 x-lock,为什么它仍然需要等待 x-lock。

有人可以帮我在mysql中重现这种死锁吗?

谢谢。

4

1 回答 1

7

我不知道您的查询,但似乎您正在将行插入子表,然后更新父表中的行。

如果这是真的,那么您在 MySQL 中遇到了这个问题:http ://bugs.mysql.com/bug.php?id=48652

如果在表上定义了 FOREIGN KEY 约束,则任何需要检查约束条件的插入、更新或删除都会在它查看的记录上设置共享记录级锁以检查约束。InnoDB 还在约束失败的情况下设置这些锁。

在您拥有的第一张表的单个记录上:

  1. 来自事务 1 集的 S 锁,
  2. 来自事务 2 集的 S 锁,
  3. 请求来自事务 1 的 X 锁,被来自事务 2 的 S 锁阻塞,
  4. 请求来自事务 2 的 X 锁,被来自事务 1 的 S 锁阻塞

可能的解决方案是先更新父表,然后将行插入子表。假设我们需要在子行插入时增加一些计数器,那么查询将是:

UPDATE <parent row> SET count = count + 1;
INSERT <child row>; /* if the INSERT fails, roll back the trx */

如果只想在插入子行后更新父行,可以使用FOR UPDATE语句对父行设置锁定:

SELECT <parent row> FOR UPDATE;
INSERT <child row>; /* if the INSERT fails, roll back the trx */
UPDATE <parent row> SET count = count + 1;
于 2013-03-06T16:51:48.690 回答