48 votes

Est-ce qu'incrémenter un champ dans MySQL est atomique?

Je suis en train de créer un site web où j'aimerais incrémenter un compteur dans une table MyISAM standard.

Exemple simplifié :

UPDATE votes SET num = num + 1;

Cela va-t-il poser des problèmes si plusieurs connexions effectuent la même requête, ou MySQL prendra-t-il soin de verrouiller la table ou autre pour s'assurer qu'il n'y a pas de conflits ?

30voto

TraderJoeChicago Points 2101

L'écriture est atomique mais une incrémentation nécessite également une lecture. Donc la question est: Êtes-vous sûr que la lecture est sûre, en d'autres termes, êtes-vous sûr qu'un autre thread faisant l'incrémentation n'obtiendra pas la même valeur à incrémenter? J'ai des doutes. La manière 100% correcte de le faire serait.

-- commencer la transaction ici

select compteur from mesCompteurs where id_compteur = 1 FOR UPDATE;

-- maintenant la ligne est verrouillée et personne ne peut lire ou modifier ses valeurs

update mesCompteurs set compteur = ? where id = 1;

-- définir ? sur compteur + 1 programmation

commit; -- et déverrouiller...

18voto

lucho Points 2320

Les tables MyISAM utilisent un verrouillage au niveau de la table. Cela signifie que toute la table sera verrouillée pendant l'exécution de votre requête de mise à jour. Donc la réponse pour votre cas d'utilisation simplifié est : oui, c'est sûr pour les threads. Mais cela peut ne pas être le cas si vous utilisez un autre moteur de stockage ou si votre mise à jour inclut plusieurs tables.

Voici une citation du manuel MySQL pour plus de clarté:

Le verrouillage de table permet à de nombreuses sessions de lire à partir d'une table en même temps, mais si une session veut écrire dans une table, elle doit d'abord obtenir un accès exclusif. Pendant la mise à jour, toutes les autres sessions qui veulent accéder à cette table particulière doivent attendre que la mise à jour soit terminée.

Vous pouvez également envisager d'utiliser des colonnes à incrémentation automatique, des transactions ou une synchronisation externe si cela correspond à votre conception.

Santé!

8voto

grahamparks Points 10187

Oui, la table (ou les lignes dans les bases de données au format InnoDB) est automatiquement verrouillée lorsque vous exécutez une requête de mise à jour.

5voto

Cette forme de UPDATE est atomique. D'autres formes de UPDATE peuvent être rendues atomiques en utilisant des transactions avec SELECT ... FOR UPDATE.

2voto

mavarazy Points 917

Avait le même problème, bien que la requête était plus compliquée:

UPDATE CLB_SYNC_T SET PENDING_MESSAGES = PENDING_MESSAGES + ? WHERE USER_ID = ?

Utiliser MyISAM comme moteur par défaut n'a pas aidé, donc je me suis rabattu sur l'utilisation de SELECT FOR UPDATE.

Avec SELECT FOR UPDATE, les performances se sont améliorées d'environ 10 fois, car MySQL n'a pas verrouillé toute la table pour effectuer une mise à jour de ligne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X