2012-08-30 30 views
1

我從SHOW ENGINE INNODB STATUS重現這種僵局在MySQL

*** (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鎖,爲什麼它仍然需要等待X鎖。

有人能幫我在mysql中重現這樣的死鎖嗎?

謝謝。

回答

6

我不知道你的查詢,但好像你插入行到子表中,然後在父表中進行更新。

如果這是真的,你打這個問題在MySQL:http://bugs.mysql.com/bug.php?id=48652

如果外鍵約束表上,任何INSERT,UPDATE定義,或刪除,需要進行檢查的約束條件在它檢查約束的記錄上設置共享記錄級鎖。在約束失敗的情況下,InnoDB也會設置這些鎖。

在第一表的單個記錄您有:

    從事務1組
  1. S鎖,
  2. 從交易2集合S鎖,從請求的交易1
  3. X鎖,阻斷從交易2 S鎖,從請求的交易2
  4. X鎖,阻止S鎖從事務1

可能的解決方案是首先更新父表,然後將行插入到子表中。假設我們需要增加在子行插入一些櫃檯,然後查詢將是:

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;