2012-12-18 3 views
5

Je sais que cela a déjà été demandé, mais je suis toujours confus et je voudrais éviter tout problème avant de commencer la programmation si possible.Comment éviter correctement les conditions de course Mysql

Je prévois d'avoir un site web interne avec au moins 100 utilisateurs actifs à un moment donné. Les utilisateurs afficheraient un élément (inséré dans db avec un 0 comme valeur) et cet élément serait affiché via un site php (requête db). Les utilisateurs obtiennent alors l'option d'appuyer sur un bouton et de verrouiller cet élément comme étant le leur (attribuer la valeur de cet élément comme leur ID)

Comment puis-je m'assurer que 2 utilisateurs ou plus ne récupèrent pas le même article en même temps? . Je sais que dans la programmation comme C++ j'utiliserais simplement le verrou ol mutex. Est-ce leur équivalent dans mysql où il verrouillera juste une entrée d'article comme ça? J'ai vu des références à LOCK_TABLES et GET_LOCK et beaucoup d'autres, donc je suis encore très confus sur ce qui serait le mieux.

Il y a un potentiel pour beaucoup de gens en course d'appuyer sur ce bouton et ce serait désastreux si plusieurs personnes obtenaient une confirmation. Je sais que c'est un excellent exemple d'une condition de concurrence, mais mysql est un territoire étranger pour moi.

Je vais évidemment interroger la valeur de l'élément avant de le mettre à jour et m'assurer qu'il n'a pas été écrit, mais quelle est la meilleure façon de s'assurer que cette condition de course est évitée.

Merci d'avance.

Répondre

2

Pour ce faire, vous devrez verrouiller l'enregistrement d'une manière ou d'une autre. Ajouter une colonne à 0. LockedBy défaut

Quand quelqu'un appuie sur le bouton exécuter une requête qui ressemble à ceci:

Table MISE A JOUR SET LockedBy = où LockedBy = 0 et id =; Après la mise à jour, vérifiez les lignes affectées (en PHP mysql_affected_rows). Si la valeur est 0, cela signifie que la requête n'a rien mis à jour car la colonne LockedBy n'est pas 0 et donc bloquée par quelqu'un d'autre.

Hope this helps

+0

Pourquoi créer une toute nouvelle colonne? ne pourriez-vous pas utiliser cette même tactique sur une colonne existante? –

2

Lorsque vous publiez une ligne, définissez la colonne à NULL, et non 0.

Ensuite, lorsqu'un utilisateur met à jour la ligne d'en faire leur propre, la mise à jour comme suit:

COALESCE() renvoie son premier argument non nul.
UPDATE MyTable SET ownership = COALESCE(ownership, $my_user_id) WHERE id = ... 

Donc, même si vous et moi mettons à jour simultanément, le premier à valider obtient la valeur. Le second ne remplacera pas cette valeur.

0

Vous pouvez envisager Transactions

BEGING TRANSACTION; 
SELECT ownership FROM ....; 
UPDATE table .....; // set the ownership if the table not owned yet 
COMMIT; 

et vous pouvez ROLLBACK toutes les requêtes entre la transaction si vous avez attrapé une erreur!

Questions connexes