Au lieu de FOR UPDATE
utilisez LOCK IN SHARE MODE
. FOR UPDATE
empêche également les autres transactions de lire la ligne. LOCK IN SHARE MODE
autorise la lecture, mais empêche la mise à jour.
Référence :Manuel MySQL
------ séance 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- session 2 (qui n'est plus bloquée :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Mise à jour :
Réaliser que la table n'a pas d'index sur t
, j'ai l'explication suivante :
Tout d'abord, la transaction T1 verrouille la ligne 1 dans SELECT * FROM test WHERE t=1 FOR UPDATE
Ensuite, la transaction T2 tente d'exécuter le test UPDATE test SET NAME='irfandd' WHERE t=4
. Pour savoir quelles lignes sont affectées, il doit analyser toutes les lignes, y compris la ligne 1 . Mais c'est verrouillé, donc T2 doit attendre que T1 se termine. S'il y a un quelconque type d'index, le WHERE t=4
peut utiliser l'index pour décider si la ligne 1 contient t=4
ou pas, donc pas besoin d'attendre.
Option 1 : ajouter un index sur test.t
afin que votre mise à jour puisse l'utiliser.
Option 2 : utilisez LOCK IN SHARE MODE
, qui est destiné à mettre un verrou en lecture uniquement. Malheureusement, cette option crée un blocage. Fait intéressant, la transaction T2 s'exécute (mise à jour de la ligne 4) et T1 échoue (mise à jour de la ligne 2). Il semble que T1 verrouille la lecture ligne 4 aussi, et puisque T2 le modifie, T1 échoue à cause du niveau d'isolement de la transaction (LECTURE RÉPÉTABLE par défaut
). La solution finale serait de jouer avec Niveaux d'isolation des transactions , en utilisant READ UNCOMMITTED
ou READ COMMITTED
niveaux de transaction.
La plus simple est Option 1 , à mon humble avis, mais cela dépend de vos possibilités.