тупик транзакции mysql

Время от времени я получаю ошибки взаимоблокировки mysql, вызванные состоянием гонки. Мне удалось воспроизвести ошибку следующим образом.

Транзакция 1
начать транзакцию
вставить в fixtradeshistory (выбрать null, fixtrades.* из fixtrades, где id=10);

Транзакция 2
начать транзакцию
вставить в fixtradeshistory (выбрать null, fixtrades.* из fixtrades, где id=10);

Транзакция 1
update fixtrades set fixtradesstatustypesid='bla', fixgatewayorderid='bla', где id=10;

Транзакция 2 DEADLOCK
update 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)

person cottaway    schedule 18.03.2011    source источник
comment
Вы также можете вставить статус show inodb ..   -  person Zimbabao    schedule 18.03.2011


Ответы (3)


Любые идеи, почему этот тупик происходит?

InnoDB имеет несколько режимов блокировки. Здесь мы видим блокировку на уровне строки, но она не работает.

Транзакция №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 аннулирует одну из двух транзакций и выполнит откат. Аналогичная ситуация описана на странице документации, на которую я ссылаюсь.

У вас есть два способа справиться с этим.

Первый и наихудший способ — выполнить блокировку таблицы вместо использования транзакции. Это предотвратит одновременное изменение таблицы несколькими авторами (или, возможно, читателями). Это, вероятно, повлияет на производительность и приведет к еще более серьезным тупиковым ситуациям. Кроме того, вы не можете смешивать блокировки таблиц и транзакции.

Второй и лучший способ — модифицировать ваше приложение, чтобы элегантно справляться с взаимоблокировками. Это означает убедиться, что откат произошел, и либо повторить попытку, либо представить пользователю соответствующую ошибку.

person Charles    schedule 18.03.2011

Поскольку транзакция 2 удерживает блокировку S(hared) на fixtrades id=10, полученную при ее чтении, попытка транзакции 1 получить исключительную блокировку для изменения записи не увенчается успехом.

Я думаю, вы могли бы решить эту проблему, изменив вставку на это:

вставить в fixtradeshistory (выбрать null, fixtrades.* из fixtrades, где id=10 ДЛЯ ОБНОВЛЕНИЯ);

person ggiroux    schedule 18.03.2011

Вы также можете решить проблему, выполнив UPDATE перед INSERT. Это приводит к тому, что транзакция 1 в первый раз получает эксклюзивную блокировку, а не общую блокировку. Транзакция 2 по-прежнему будет зависать в ожидании завершения транзакции 1. Но транзакция 1 сможет завершиться, потому что у нее уже есть необходимая монопольная блокировка.

Подробнее см. http://vimeo.com/12941188.

person phylae    schedule 04.06.2011