2016-12-05 15 views
2

別の接続デッドロックでSELECT ... FOR UPDATEおよびINSERT INTO文に問題があります。プロセスで複数のSELECT ... FOR UPDATEを遅延INSERT INTOで実行

function locate(array values) { 

    BEGIN TRANSACTION; 

    rows = SELECT * FROM tblFoo WHERE id IN values FOR UPDATE; 

    if (rows is empty) { 
     sleep(10); // i.e., do some stuff 
     rows = INSERT INTO tblFoo (id) VALUES values; 
    } 

    COMMIT; 

    return rows; 
} 

@ t = 0の:

主キーidと空の表tblFooを考えると、以下の擬似コードを考えるreturn locate([1,2,3]);プロセスBの@ tに

= 1:return locate([1]);


私の期待は、id S 1と1になるギャップロック行、2というプロセスであります3はプロセスAのトランザクションがコミットされるまでSELECT ... FOR UPDATEにプロセスBをブロックします。コミットされると、プロセスBがブロックされていない取得しid 1と行を返すだけで、プロセスAによって挿入された

観察された行動は、プロセスAがロールバックさせ、デッドロックが発生することで、プロセスBはidと行を挿入1.

MySQLがこのように動作している理由を理解できたら助けてください。

私はMySQLバージョン5.5でinnoDBを使用しています。

編集は、次のテーブル構造

CREATE TABLE `tblFoo` (
    `id` INT(11) NOT NULL, 
    PRIMARY KEY (`id`) 
) 
COLLATE='utf8mb4_unicode_ci' 
ENGINE=InnoDB 
; 

編集2です:次は、デッドロックを詳述のInnoDB状態である

------------------------ 
LATEST DETECTED DEADLOCK 
------------------------ 
161205 15:55:50 
*** (1) TRANSACTION: 
TRANSACTION 32A3E743A, ACTIVE 3 sec inserting 
mysql tables in use 1, locked 1 
LOCK WAIT 4 lock struct(s), heap size 1248, 2 row lock(s) 
MySQL thread id 12243323, OS thread handle 0x7fd7dd47f700, query id 4713227035 localhost root update 
INSERT INTO test.tblFoo (id) VALUES (1) 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 1556528 n bits 72 index `PRIMARY` of table `test`.`tblFoo` trx id 32A3E743A lock_mode X locks gap before rec insert intention waiting 
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 4; hex 80000002; asc  ;; 
1: len 6; hex 00032a3e5f6b; asc *>_k;; 
2: len 7; hex b30017d06b0110; asc  k ;; 

*** (2) TRANSACTION: 
TRANSACTION 32A3E5FD3, ACTIVE 5 sec inserting 
mysql tables in use 1, locked 1 
4 lock struct(s), heap size 1248, 5 row lock(s) 
MySQL thread id 12243319, OS thread handle 0x7fd7f0097700, query id 4713230393 localhost root update 
INSERT INTO test.tblFoo (id) VALUES (1),(2),(3) 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 0 page no 1556528 n bits 72 index `PRIMARY` of table `test`.`tblFoo` trx id 32A3E5FD3 lock_mode X 
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 
0: len 8; hex 73757072656d756d; asc supremum;; 

Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 4; hex 80000005; asc  ;; 
1: len 6; hex 00032a38e424; asc *8 $;; 
2: len 7; hex cc001c166a0110; asc  j ;; 

Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 4; hex 80000002; asc  ;; 
1: len 6; hex 00032a3e5f6b; asc *>_k;; 
2: len 7; hex b30017d06b0110; asc  k ;; 

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 1556528 n bits 72 index `PRIMARY` of table `test`.`tblFoo` trx id 32A3E5FD3 lock_mode X locks gap before rec insert intention waiting 
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 4; hex 80000002; asc  ;; 
1: len 6; hex 00032a3e5f6b; asc *>_k;; 
2: len 7; hex b30017d06b0110; asc  k ;; 

*** WE ROLL BACK TRANSACTION (2) 
+0

私は 'id'が' PRIMARY KEY'だと思いますが、とにかくあなたのテーブル構造を表示してください。 – bishop

+0

@bishopメインポストにテーブル構造を追加しました – MrDiggles

+0

'sleep(10)'他の活動を表現するために入れたと思います。彼らは実際に10秒かかりますか?もしそうであれば、それほど続くトランザクションを開くことはお勧めしません。 – FDavidov

答えて

0

私はあることを、何が起こっているかと思います2つの取引を開始します。どちらも同じテーブルの "select ... for update"を取得します。更新の前に2番目のトランザクションが待機することが予想されます。しかし、文書https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.htmlからはそうではないように聞こえます(これはあなたが見ている動作です)。したがって、両方の "choose ... for update"はお互いをブロックし、デッドロックを残します。

+0

ドキュメントを見ると、あなたが正しいと思われます。私の問題には解決策がないようです。つまり、多分何らかのミューテックステーブルを実装する必要があります。誰かが明確な説明(あるいはおそらく解決策)を提示しない限り、私はこの答えを受け入れます。努力をいただきありがとうございます。 – MrDiggles

関連する問題