mysql事务死锁

Posted

技术标签:

【中文标题】mysql事务死锁【英文标题】:mysql transaction deadlock 【发布时间】:2011-03-18 15:06:52 【问题描述】:

我不时收到由竞争条件引起的 mysql 死锁错误。我已经设法用以下方法复制了错误。

交易 1 开始交易 插入 fixtradeshistory (select null, fixtrades.* from fixtrades where id=10);

交易 2 开始交易 插入 fixtradeshistory (select null, fixtrades.* from fixtrades where id=10);

交易 1 update fixtrades set fixtradesstatustypesid='bla', fixgatewayorderid='bla' where id=10;

事务 2 死锁 update fixtrades set fixtradesstatustypesid='bla', fixgatewayorderid='bla' where 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)

【问题讨论】:

你也可以粘贴“显示 inodb 状态”.. 【参考方案1】:

任何想法为什么会发生这种死锁?

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 将杀死两个事务之一并执行回滚。我链接的文档页面上描述了类似的情况。

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

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

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

【讨论】:

【参考方案2】:

因为事务 2 在读取它时获得了 fixtrades id=10 上的 S(hared) 锁,因此事务 1 尝试获取排他锁以修改记录的尝试无法成功。

我认为您可以通过将插入更改为此来解决此问题:

插入 fixtradeshistory(从 id=10 的 fixtrades 中选择 null,fixtrades.* FOR UPDATE);

【讨论】:

【参考方案3】:

您还可以通过在 INSERT 之前执行 UPDATE 来解决问题。这会导致事务 1 第一次获得排他锁,而不是共享锁。事务 2 仍将卡住等待事务 1 完成。但是事务 1 将能够完成,因为它已经拥有所需的排他锁。

请参阅http://vimeo.com/12941188 以获得更完整的说明。

【讨论】:

以上是关于mysql事务死锁的主要内容,如果未能解决你的问题,请参考以下文章

怎么避免mysql死锁

MySQL——事务

mysql CREATE临时表+事务导致死锁

mysql 中的 latch锁和Tlock(事务锁), DML加锁规则,以及死锁分析。

解决一次mysql死锁问题

[MySQL] mysql的事务隔离和幻读和死锁问题