Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Deadlock mit SELECT ... FOR UPDATE in MySQL

Was funktioniert und was nicht

Eine Möglichkeit, beide Transaktionen ohne Deadlock durchlaufen zu lassen, besteht darin, Isolationsstufe bis READ COMMITED (oder UNBESCHRIEBEN LESEN ) in beiden Verbindungen:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

(vor start transaction ).

Wahrscheinlich würde es ausreichen, es in t2 zu setzen , aber nur um für das Beispiel sicherzugehen, legen Sie es in beiden fest.

Das Ändern der Isolationsstufe von Transaktionen bringt einige Nebenwirkungen mit sich, über die man sich informieren sollte im Handbuch bevor Sie dies in einer Produktionsumgebung ändern.

Statusinformationen zum Deadlock

------------------------
LATEST DETECTED DEADLOCK
------------------------
140424  8:45:46
*** (1) TRANSACTION:
TRANSACTION B6F18A3, ACTIVE 5 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 13885, OS thread handle 0x7f8b1dbd2700, query id 901012
 localhost root statistics
SELECT * FROM t WHERE id = 1 FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
 `test`.`t` trx id B6F18A3 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 00000b6f1883; asc    o  ;;
 2: len 7; hex 06000059a211ea; asc    Y   ;;
 3: len 5; hex 48656c6c6f; asc Hello;;

*** (2) TRANSACTION:
TRANSACTION B6F18A2, ACTIVE 10 sec starting index read
mysql tables in use 1, locked 1
3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 13888, OS thread handle 0x7f8b1f64d700, query id 901068
 localhost root Updating
UPDATE t SET `descc` = 'Hello from t1'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
 `test`.`t` trx id B6F18A2 lock_mode X locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 00000b6f1883; asc    o  ;;
 2: len 7; hex 06000059a211ea; asc    Y   ;;
 3: len 5; hex 48656c6c6f; asc Hello;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
 `test`.`t` trx id B6F18A2 lock_mode X waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 00000b6f1883; asc    o  ;;
 2: len 7; hex 06000059a211ea; asc    Y   ;;
 3: len 5; hex 48656c6c6f; asc Hello;;

*** WE ROLL BACK TRANSACTION (1)

Erklärung

Wie a_horse_with_no_name erwähnte, scheint dies ein Fehler in MySQL zu sein. Transaktion (2) möchte eine Gap-Sperre für dieselbe Zeile erhalten, in der sie bereits eine X-Sperre hält. Transaktion (1) wartet auf eine Non-Gap-X-Sperre auf dieser Zeile. Es ist mir nicht klar, warum diese Anfragen widersprüchlich sein sollten. Festlegen der Isolationsstufe auf READ COMMITTED deaktiviert die Lückenverriegelung. Da das Beispiel dann funktioniert, ist dies ein Hinweis darauf, dass Gap-Locking hier tatsächlich das Problem ist.