2012-12-18 8 views
5

Ich weiß, dass dies schon einmal gefragt wurde, aber ich bin immer noch verwirrt und möchte irgendwelche Probleme vermeiden, bevor ich in die Programmierung gehe, wenn möglich.Wie man Mysql Race Conditions richtig vermeidet

Ich plane eine interne Website mit mindestens 100 aktiven Benutzern zu jeder Zeit. Benutzer würden ein Element veröffentlichen (eingefügt in db mit einer 0 als Wert) und dieses Element würde über eine PHP-Site (DB-Abfrage) angezeigt werden. Benutzer erhalten dann die Option, eine Schaltfläche zu drücken und diesen Artikel als ihren zu sperren (den Wert dieses Artikels als ihre ID zuweisen)

Wie stelle ich sicher, dass 2 oder mehr Benutzer nicht den gleichen Artikel zur gleichen Zeit abrufen . Ich weiß, in der Programmierung wie C++ würde ich einfach ol Mutex-Sperre verwenden. Ist das ein Äquivalent in mysql, wo es nur einen Eintrag wie diesen blockiert? Ich habe Referenzen zu LOCK_TABLES und GET_LOCK und vielen anderen gesehen, daher bin ich immer noch sehr verwirrt darüber, was das Beste wäre.

Es gibt Potential für viele Leute, die alle Rennen fahren, um diesen einen Knopf zu drücken, und es wäre katastrophal, wenn mehrere Leute eine Bestätigung bekommen würden.

Ich weiß, dies ist ein Paradebeispiel für eine Race Condition, aber Mysql ist fremdes Territorium für mich.

Ich werde natürlich den Wert des Elements abfragen, bevor ich es aktualisiere und sicherstellen, dass es nicht geschrieben hat, aber was ist der beste Weg, um sicherzustellen, dass diese Race-Bedingung vermieden wird.

Vielen Dank im Voraus.

Antwort

2

Um dies zu erreichen, müssen Sie den Datensatz irgendwie sperren. Hinzufügen einer Spalte zu LockedBy säumige 0.

Wenn jemand die Schaltfläche, um eine Abfrage ähnelt dieses auszuführen drückt:

SET

UPDATE Tabelle LockedBy = WHERE LockedBy = 0 und id =;

Nach dem Update überprüfen Sie die betroffenen Zeilen (in PHP mysql_affected_rows). Wenn der Wert 0 ist, bedeutet dies, dass die Abfrage nichts aktualisiert hat, weil die Spalte "LockedBy" nicht 0 ist und daher von jemand anderem gesperrt wurde.

this helps

+0

Warum eine ganz neue Spalte erstellen? Könnten Sie nicht einfach dieselbe Taktik für eine vorhandene Spalte verwenden? –

2

Wenn Sie eine Zeile schreiben, stellen Sie die Spalte auf NULL, nicht 0

Dann, wenn ein Benutzer die Zeile aktualisiert, um es zu eigen zu machen, aktualisieren Sie es wie folgt:

UPDATE MyTable SET ownership = COALESCE(ownership, $my_user_id) WHERE id = ... 

COALESCE() gibt sein erstes Nicht-Null-Argument zurück. Selbst wenn Sie und ich gleichzeitig aktualisieren, kann der erste Commit den Wert setzen. Die zweite wird diesen Wert nicht überschreiben.

0

Sie können Transaktionen betrachten

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

und auch Sie können alle Abfragen zwischen dem Transaktions-Rollback, wenn Sie einen Fehler erwischt!