mysql事务死锁

cot*_*way 5 mysql deadlock

由于竞争条件,我不时会遇到mysql死锁错误.我已设法使用以下内容复制错误.

事务1
启动事务
插入到fixtradeshistory(从fixtrades中选择null,fixtrades.*,其中id = 10);

事务2
启动事务
插入到fixtradeshistory(从fixtrades中选择null,fixtrades.*,其中id = 10);

事务1
更新fixtrades设置fixtradesstatustypesid ='bla',fixgatewayorderid ='bla',其中id = 10;

交易2 DEADLOCK
更新fixtrades设置fixtradesstatustypesid ='bla',fixgatewayorderid ='bla',其中id = 10;

任何想法为什么会发生这种僵局?

------------------------
LATEST DETECTED DEADLOCK
------------------------
110317 14:52:08
(1) TRANSACTION:
TRANSACTION 0 57841252, ACTIVE 16 sec, process no 2976, OS thread id 3030973328 starting index read`
mysql tables in use 1, locked 1
LOCK WAIT 15 lock struct(s), heap size 1024, undo log entries 1
MySQL thread id 326855, query id 2689051 localhost salert Updating
update fixtrades set fixtradesstatustypesid='orderplaced', fixgatewayorderid='BANZAI>EXEC:1288679244240:520703' where id=10
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 232059 n bits 136 index PRIMARY` of table `salert/fixtrades` trx id 0 57841252 lock_mode X locks rec but not gap waiting
Record lock, heap no 66 PHYSICAL RECORD: n_fields 26; compact format; info bits 0
0: len 4; hex 8000000a; asc     ;; 1: len 6; hex 00000371a2cd; asc    q  ;; 2: len 7; hex 000004f8400770; asc     @ p;; 3: len 4; hex 80000004; asc     ;; 4: len 4; hex 80000004; asc     ;; 5: len 4; hex 80000364; asc    d;; 6: len 4; hex 800040aa; asc   @ ;; 7: SQL NULL; 8: len 13; hex 6f726465726163636570746564; asc orderaccepted;; 9: len 30; hex 42414e5a41493e455845433a313238383637393234343234303a35323037; asc BANZAI>EXEC:1288679244240:5207;...(truncated); 10: SQL NULL; 11: len 8; hex 73656c6c6c6f6e67; asc selllong;; 12: len 5; hex 564f442e4c; asc VOD.L;; 13: len 3; hex 313030; asc 100;; 14: SQL NULL; 15: SQL NULL; 16: len 4; hex 4d80e0cc; asc M   ;; 17: SQL NULL; 18: SQL NULL; 19: SQL NULL; 20: len 6; hex 6d61726b6574; asc market;; 21: SQL NULL; 22: SQL NULL; 23: SQL NULL; 24: SQL NULL; 25: SQL NULL;

*** (2) TRANSACTION:
TRANSACTION 0 57841255, ACTIVE 7 sec, process no 2976, OS thread id 3030371216 starting index read, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
15 lock struct(s), heap size 1024, undo log entries 1
MySQL thread id 326860, query id 2689066 localhost salert Updating
update fixtrades set fixtradesstatustypesid='orderplaced', fixgatewayorderid='BANZAI>EXEC:1288679244240:520703' where id=10
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 232059 n bits 136 index `PRIMARY` of table `salert/fixtrades` trx id 0 57841255 lock mode S locks rec but not gap
Record lock, heap no 66 PHYSICAL RECORD: n_fields 26; compact format; info bits 0
0: len 4; hex 8000000a; asc     ;; 1: len 6; hex 00000371a2cd; asc    q  ;; 2: len 7; hex 000004f8400770; asc     @ p;; 3: len 4; hex 80000004; asc     ;; 4: len 4; hex 80000004; asc     ;; 5: len 4; hex 80000364; asc    d;; 6: len 4; hex 800040aa; asc   @ ;; 7: SQL NULL; 8: len 13; hex 6f726465726163636570746564; asc orderaccepted;; 9: len 30; hex 42414e5a41493e455845433a313238383637393234343234303a35323037; asc BANZAI>EXEC:1288679244240:5207;...(truncated); 10: SQL NULL; 11: len 8; hex 73656c6c6c6f6e67; asc selllong;; 12: len 5; hex 564f442e4c; asc VOD.L;; 13: len 3; hex 313030; asc 100;; 14: SQL NULL; 15: SQL NULL; 16: len 4; hex 4d80e0cc; asc M   ;; 17: SQL NULL; 18: SQL NULL; 19: SQL NULL; 20: len 6; hex 6d61726b6574; asc market;; 21: SQL NULL; 22: SQL NULL; 23: SQL NULL; 24: SQL NULL; 25: SQL NULL;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 232059 n bits 136 index `PRIMARY` of table `salert/fixtrades` trx id 0 57841255 lock_mode X locks rec but not gap waiting
Record lock, heap no 66 PHYSICAL RECORD: n_fields 26; compact format; info bits 0
0: len 4; hex 8000000a; asc     ;; 1: len 6; hex 00000371a2cd; asc    q  ;; 2: len 7; hex 000004f8400770; asc     @ p;; 3: len 4; hex 80000004; asc     ;; 4: len 4; hex 80000004; asc     ;; 5: len 4; hex 80000364; asc    d;; 6: len 4; hex 800040aa; asc   @ ;; 7: SQL NULL; 8: len 13; hex 6f726465726163636570746564; asc orderaccepted;; 9: len 30; hex 42414e5a41493e455845433a313238383637393234343234303a35323037; asc BANZAI>EXEC:1288679244240:5207;...(truncated); 10: SQL NULL; 11: len 8; hex 73656c6c6c6f6e67; asc selllong;; 12: len 5; hex 564f442e4c; asc VOD.L;; 13: len 3; hex 313030; asc 100;; 14: SQL NULL; 15: SQL NULL; 16: len 4; hex 4d80e0cc; asc M   ;; 17: SQL NULL; 18: SQL NULL; 19: SQL NULL; 20: len 6; hex 6d61726b6574; asc market;; 21: SQL NULL; 22: SQL NULL; 23: SQL NULL; 24: SQL NULL; 25: SQL NULL;

*** WE ROLL BACK TRANSACTION (2)
Run Code Online (Sandbox Code Playgroud)

Cha*_*les 8

任何想法为什么会发生这种僵局?

InnoDB有许多锁定模式.我们在这里看到一个行级锁定,但它失败了.

事务#1正在等待独占锁:

RECORD LOCKS ... page no 232059 ... lock_mode X locks rec but not gap waiting
Run Code Online (Sandbox Code Playgroud)

事务#2 已经在同一行上有一个共享锁:

RECORD LOCKS ... page no 232059 ... lock mode S locks rec but not gap
Run Code Online (Sandbox Code Playgroud)

虽然#2有共享锁,但它还需要一个独占锁:

RECORD LOCKS ... page no 232059 ... lock_mode X locks rec but not gap waiting
Run Code Online (Sandbox Code Playgroud)

#1和#2都需要相同的独占锁,但在#2 释放共享锁之前不能授予任何锁,但是#2在升级到独占锁之前无法释放共享锁,但这种情况永远不会发生.

这会导致死锁,InnoDB将终止两个事务中的一个并执行回滚.我链接的文档页面描述了类似的情况.

你有两种方法来处理这个问题.

第一种也是最糟糕的方法是执行表锁定而不是使用事务.这将防止多个编写器(或可选的读取器)立即修改表.这可能会影响性能,并打开更糟糕的死锁情况.此外,您不能混合表锁和事务.

第二种也是更好的方法是修改你的应用程序以优雅地处理死锁.这意味着确保回滚发生并再次尝试或向用户显示适当的错误.