Mysql
 sql >> Base de données >  >> RDS >> Mysql

Verrouillage au niveau de la ligne dans MySQL

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.