我不时会因竞争条件而遇到mysql死锁错误。我已设法使用以下内容复制错误。
交易1
开始交易
插入fixtradeshistory(从fixtrades中选择null,fixtrades。*,其中id = 10);
交易2
开始交易
插入fixtradeshistory(从fixtrades中选择null,fixtrades。*,其中id = 10);
交易1
更新fixtrades set fixtradesstatustypesid ='bla',fixgatewayorderid ='bla',其中id = 10;
交易2 DEADLOCK
更新fixtrades set 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)
答案 0 :(得分:7)
为什么会出现这种僵局?
InnoDB has a number of locking modes。我们在这里看到了行级锁定,但它失败了。
交易#1正在等待独占锁:
RECORD LOCKS ... page no 232059 ... lock_mode X locks rec but not gap waiting
事务#2 已在同一行上拥有共享锁:
RECORD LOCKS ... page no 232059 ... lock mode S locks rec but not gap
虽然#2有共享锁,但也想要一个独占锁:
RECORD LOCKS ... page no 232059 ... lock_mode X locks rec but not gap waiting
#1和#2都需要相同的独占锁,但在#2 释放共享锁之前不能授予任何锁,但#2无法释放共享锁,直到它升级为独占,但这永远不会发生。
这导致死锁,InnoDB将终止两个事务中的一个并执行回滚。我链接的文档页面描述了类似的情况。
你有两种方法可以解决这个问题。
第一种也是最糟糕的方法是执行表锁定而不是使用事务。这将防止多个编写器(或可选的读取器)立即修改表。这可能会影响性能,并打开更糟糕的死锁情况。此外,您不能混合表锁和事务。
第二种更好的方法是修改您的应用程序以优雅地处理死锁。这意味着确保回滚发生并再次尝试或向用户显示适当的错误。
答案 1 :(得分:1)
因为事务2在fixtrades id = 10上持有S(hared)锁,在读取它时获取,所以事务1试图获得一个eXclusive锁来修改记录不会成功。
我认为您可以通过将插入更改为此来解决此问题:
插入fixtradeshistory(从fixtrades中选择null,fixtrades。*,其中id = 10 FOR UPDATE);
答案 2 :(得分:1)
您也可以通过在INSERT之前执行UPDATE来解决问题。这会导致事务1第一次获得独占锁,而不是共享锁。交易2仍将等待交易1完成。但事务1将能够完成,因为它已经拥有它所需的独占锁。
有关更完整的说明,请参阅http://vimeo.com/12941188。