2010-12-05 5 views
26

Je crée un site web où je voudrais incrémenter un compteur dans une table MyISAM standard.Est incrémentation d'un champ dans MySQL atomique?

Exemple simplifié:

UPDATE votes SET num = num + 1; 

Est-ce que cette cause des problèmes si plusieurs connexions font la même requête, ou va MySQL prendre soin et verrouiller la table ou quelque chose pour vous assurer qu'il n'y a pas de conflit?

+0

Vous pourriez également être intéressé par ma réponse à une autre question de verrouillage: http://stackoverflow.com/questions/3312361/does-this-lock -the-database/3312790 # 3312790 – Mike

Répondre

12

Les tables MyISAM utilisent le verrouillage au niveau de la table. Cela signifie que toute la table sera verrouillée lors de l'exécution de votre requête de mise à jour. Donc, la réponse à votre cas d'utilisation simplifié est: oui, ceci 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 lues à partir d'une table en même temps, mais si une session veut écrire à une table , il doit d'abord obtenir l'accès exclusif . Pendant la mise à jour, toutes les autres sessions qui souhaitent accéder à cette table particulière doivent attendre que la mise à jour soit terminée.

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

À la votre!

3

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

4

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

18

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

-- begin transaction here 

select counter from myCounters where counter_id = 1 FOR UPDATE; 

-- now the row is locked and nobody can read or modify its values 

update myCounters set counter = ? where id = 1; 

-- set ? to counter + 1 programmatically 

commit; -- and unlock... 
+1

Je suis à peu près certain que l'exemple OP du champ UPDATE SET = field + 1 ne causera pas de problèmes de simultanéité, mais c'est le meilleur moyen de s'assurer que vous verrouillez la ligne/table en modifiant un champ. Cela a généralement plus de sens quand vous faites une opération plus complexe. – Nicholi

0

eu le même problème, même si la requête était plus compliquée:

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

En utilisant MyISAM comme moteur par défaut n'a pas aidé, donc je REPLI à SELECT pour une utilisation UPDATE.

Avec SELECT FOR UPDATE performance améliorée ~ 10 fois, puisque MySQL n'a pas verrouillé toute la table, pour faire une mise à jour de ligne.

0

Une autre approche lors de l'utilisation InnoDB utilise index unique sur plusieurs colonnes comme suit:

Table 'Sessions' { UNIQUE_KEY (browser_session_id, profile_id) // veille à ce que l'insertion d'une entrée par session aura lieu une fois }

select count (de browser_session_id) des sessions

garantira r esult de sessions uniques, car plusieurs sessions par utilisateur ne sont pas autorisées.

Conclusions

  • Advantage

    Chaque insert nécessite une pré-sélection.

  • Inconvénient

    Il ne convient pas à tous les cas.

    peut ralentir les performances d'écriture et nécessite une gestion supplémentaire

Questions connexes