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 が ship にあります。

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 に答える