web-dev-qa-db-fra.com

Comment interroger et augmenter une valeur (compteur) de manière thread-safe? (éviter les conditions de course)

Dans un tableau où chaque ligne a un compteur (juste une valeur entière), j'ai besoin d'obtenir la valeur actuelle et de l'augmenter en même temps.

Effectivement, je veux faire ceci:

SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123

Mais faire cela comme deux requêtes n'est évidemment pas thread-safe: plusieurs processus faisant la même chose (sur la même ligne) peuvent obtenir la même valeur de compteur. J'ai besoin que tous soient uniques, donc chaque processus obtiendrait la valeur actuelle réelle et l'augmenterait d'une unité.

Je peux penser à une construction où j'implémente un verrou manuel par ligne, mais je me demande s'il y a un moyen plus simple de le faire?

10
RocketNuts

Les déclarations de mise à jour fonctionnent parfaitement bien sans le sélectionner avant! Étant donné que les instructions simples sont sûres par définition, même deux requêtes UPDATE effectuées en même temps uniquement entraîneront une incrémentation de la ligne deux fois.

Si vous voulez réellement sélectionner la valeur de votre script PHP, faites quelque chose avec lui et souhaitez mettre à jour cette valeur de compteur exacte, vous pouvez faire ce qui suit:

BEGIN;
SELECT `counter` FROM `table` WHERE `id` = 123 FOR UPDATE;
UPDATE `table` SET `counter` = `counter`+1 WHERE `id` = 123;
COMMIT;

Cela démarre une nouvelle transaction, puis sélectionne les lignes que vous souhaitez mettre à jour et les verrouille exclusivement. Vous pouvez ensuite les mettre à jour en toute sécurité sans vous soucier des autres clients qui modifient leur contenu ou même qui accèdent aux lignes verrouillées. Enfin, vous devez valider vos modifications.

Vous devriez également lire quelque chose sur niveaux d'isolement . Vous ne voulez probablement pas une valeur comme READ UNCOMMITTED comme niveau d'isolement. Tout le reste devrait convenir à ce cas d'utilisation.

15
GhostGambler