Ce qui fonctionne et ce qui ne fonctionne pas
Une façon de faire passer les deux transactions sans blocage est de changer le niveau d'isolement pour LIRE COMMITED (ou LIRE SANS ENGAGEMENT ) dans les deux connexions :
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
(avant de start transaction
).
Il suffirait probablement de le définir dans t2
, mais juste pour être sûr de l'exemple, définissez-le dans les deux.
Changer le niveau d'isolement des transactions introduit des effets secondaires, dont il faut informer dans le manuel avant de modifier cela dans un environnement de production.
Informations d'état concernant le blocage
------------------------
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)
Explication
Comme mentionné par a_horse_with_no_name, cela ressemble à un bogue dans MySQL. La transaction (2) souhaite obtenir un verrou d'espacement sur la même ligne qu'elle détient déjà un verrou X. La transaction (1) attend un verrou X sans espace sur cette ligne. Je ne comprends pas pourquoi ces demandes devraient entrer en conflit. Définition du niveau d'isolement sur READ COMMITTED
désactive le verrouillage des espaces. Puisque l'exemple fonctionne alors, c'est un indice que le blocage des espaces est en effet le problème ici.