別の接続デッドロックで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)
私は 'id'が' PRIMARY KEY'だと思いますが、とにかくあなたのテーブル構造を表示してください。 – bishop
@bishopメインポストにテーブル構造を追加しました – MrDiggles
'sleep(10)'他の活動を表現するために入れたと思います。彼らは実際に10秒かかりますか?もしそうであれば、それほど続くトランザクションを開くことはお勧めしません。 – FDavidov