Qué funciona y qué no
Una forma de hacer que ambas transacciones se ejecuten sin interbloqueo es cambiar nivel de aislamiento para LEER COMPROMETIDO (o LEER SIN COMPROMISO ) en ambas conexiones:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
(antes de start transaction
).
Probablemente sería suficiente configurarlo en t2
, pero solo para estar seguro del ejemplo, configúrelo en ambos.
Cambiar el nivel de aislamiento de las transacciones introduce algunos efectos secundarios, sobre los cuales se debe informar en el manual antes de cambiar esto en un entorno de producción.
Información de estado sobre interbloqueo
------------------------
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)
Explicación
Como se mencionó a_horse_with_no_name, esto parece un error en MySQL. La transacción (2) quiere obtener un bloqueo de espacio en la misma fila que ya tiene un bloqueo X. La transacción (1) espera un bloqueo X sin espacio en esta fila. No me queda claro por qué estas solicitudes deberían entrar en conflicto. Establecer el nivel de aislamiento en READ COMMITTED
desactiva el bloqueo de huecos. Dado que el ejemplo funciona entonces, esta es una pista de que el bloqueo de brechas es el problema aquí.