2009-11-11 7 views
7

Ich habe in letzter Zeit einige Web-Entwicklungsarbeiten in PHP gemacht, die mich dazu gebracht haben, die Sprache im Allgemeinen zu studieren. Bis jetzt musste ich es nicht benutzen, um mit einer Datenbank zu interagieren, aber ich weiß, dass es viele praktische Funktionen dafür bietet.PHP und Nebenläufigkeit

Obwohl ich grundlegende SQL kenne und mit grundlegender Manipulation von Daten in einer Datenbank gearbeitet habe, verstehe ich nicht, wie Webentwickler, die ihre Websites um PHP/Javascript/SQL aufbauen, Benutzer, die die gleichen Daten bearbeiten, verwalten können gleiche Zeit.

Nehmen wir zum Beispiel an, Sie haben eine Blackjack-Website, die Benutzer in eines von zwei Teams teilt, wenn sie sich anmelden. Jedes Mal, wenn ein Nutzer ein Spiel gewinnt, wird ein Teil seiner Gewinne zu einer laufenden Summe für dieses Team addiert.

lässt also die Pseudo-Code sagen für die Funktion, tut dies etwa wie folgt aussieht:

... 
$total = mysql_query("SELECT score FROM team1"); 
$total = $total + $mytotal; 
mysql_query("UPDATE team1 SET score='".$total."'"); 
... 

Wenn zwei Spieler gleichzeitig spielen, ist es sehr gut möglich, dass sie beide vor dem anderen SELECT nennen Man hat die Möglichkeit, die Tabelle zu inkrementieren und zu aktualisieren, so dass Änderungen eines Benutzers sofort überschrieben werden.

Meine Frage ist, wie vermeidet man das? Ist es mit PHP auf der Code-Ebene gemacht, oder gibt es Funktionen, die von der Datenbank zur Verfügung gestellt werden, die Sie verwenden, um dies zu verhindern?

Ich habe einige Nachforschungen gemacht, und es scheint, dass PHP bietet einen semaphore Mechanismus, und ich habe auch festgestellt, dass mysql bietet eine LOCK table feature. Ich bin mir jedoch nicht sicher, welche von beiden in der Praxis verwendet wird.

Antwort

5

Wenn Ihr Problem in der realen Welt größer als dieses einfache Beispiel ist, sollten Sie eine Transaktion in Verbindung mit Sperrtabellen verwenden, um sicherzustellen, dass Benutzer sich nicht gegenseitig überschreiben.

+0

Vielen Dank an alle für mehrere große Antworten, die ich vom Lernen bin - aber ich mehr war auf der Suche für das, was in komplexeren Problemen Gleichzeitigkeit denen PHP die beste Praxis ist, wo Eine einzelne Zeile von SQL passt nicht. (Sorry, wenn mein Beispiel dazu irreführend war) –

11

Behalten Sie die Logik in der DB, diese Semantik wurde meist für Sie gelöst.

update teams 
set score = score + 1 
where team_id = 1 

.. oder welche Punktzahl und welche Teamnummer.

1

Die Datenbank verwaltet das gleichzeitige Sperren und stellt sicher, dass Änderungen automatisch vorgenommen werden. Dies ist ein Vorteil der Verwendung einer Datenbank, die ACID Transaktionen unterstützt.

In den meisten Fällen sind die Änderungen so schnell, dass die Sperrkonflikte minimal sind. Es kann jedoch immer noch passieren, dass Sie nach dem Ausführen einer SQL-Abfrage den Fehlerstatus überprüfen müssen. Die mysql_query() Funktion gibt FALSE zurück, wenn ein Problem auftritt.

Dann können Sie herausfinden, die Ursache (Update-Konflikt, unzureichende Berechtigungen, SQL-Syntaxfehler, etc.) durch den Aufruf mysql_errno(). Siehe http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html für den MySQL-Fehlercode.

1

Ich stimme mit Xepochs Antwort überein, führe keine Nebenläufigkeitsprobleme ein, außer du musst es unbedingt tun. Für eine gute Antwort bezüglich verschiedener Verriegelungsstrategien siehe here.

4

Die wichtigsten Datenbanken sind für solche Situationen ausgelegt.

Bei Verwendung von MySQL verfügt die InnoDB-Speicher-Engine über die Funktion zum Sperren von Zeilen, die die Zeile sperrt, in die geschrieben wird. Daher wartet jede Aktualisierungsanforderung für dieselbe Zeile, bis die vorherige Operation für die Zeile abgeschlossen ist.

Wenn Sie die MyISAM-Speicher-Engine verwenden, wird die gesamte Tabelle gesperrt, wenn eine Zeile aktualisiert wird. Das erzeugt einen Choke auf dem Server, wenn mehrere Spieler gleichzeitig Aktualisierungsanforderungen pushen. Es geht also darum, welche Datenbank und vor allem welche Speicher-Engine Sie für diesen Zweck verwenden.

+0

+1 Was ist die mysql-Zeile, die die Syntax sperrt? –

+0

Zeilen, die aktualisiert werden sollen, werden automatisch in InnoDB gesperrt. Wenn Sie Zeilen sperren möchten, wenn Sie sie in einer Transaktion lesen, können Sie entweder SELECT ... FOR UPDATE oder SELECT ... LOCK IN SHARE MODE verwenden. Für die Unterschiede würde ich diesen Teil des MySQL Referenzhandbuchs empfehlen: http://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html – Nirmal

1

Ich kann nicht glauben, dass keine der obigen Antworten darauf hinweist, dass Sie möglicherweise in einen Designfehler geraten.

Ja, alle Antworten sind korrekt, mysql kann Rennbedingungen und sich gegenseitig ausschließenden Zugriff auf Tabellen behandeln.

Wenn Sie jedoch auf ein Problem wie dieses stoßen, ist es wahrscheinlich Zeit, Ihr Design zu überdenken. Warum behalten Sie keine Nutzer-ID für jeden, der einen Teil ihrer Gewinne hinzugefügt hat? Du könntest dann eine haben:

INSERT INTO team1(userid, amount) VALUES(32, 100); 
    SELECT SUM(amount) FROM team1 
or 
    REPLACE INTO team1 SET amount = $total 

Aber wenn ich es wäre, würde ich nicht einmal stören. Ich würde einfach set_cookie (team_score, team_score + betrag) und alles clientseitig behalten. Wenn ich das Ergebnis lesen möchte, würde ich eine AJAX-Anfrage auslösen, um auf dem Server zu lesen oder zu schreiben und die Client-Schnittstelle trotzdem asynchron zu aktualisieren. Da Sie darauf hinweisen, dass Ihre Web-Entwicklung grundlegend ist, empfehle ich Ihnen, sich das jQuery-Framework für die asynchrone Client-Server-Kommunikation anzusehen, da dies der einfachste Weg ist, dies zu erreichen.

EDIT: Und für das Problem der jeden UI aktualisieren, wenn ein anderer Spieler einen Betrag zur Partitur fügt, schlage ich Ihnen Backbone.js Blick in das schön Ihr Datenmodell Strumpfhosen an den Client der Spieler, so dass sie sofort bekommen aktualisiert, wenn sich der Spielstand ändert.

0

Datenbanken verfügen über eine integrierte Steuerung des gemeinsamen Zugriffs, z. B. können Sie über die Gleichzeitigkeitssteuerung für PostgreSQL here lesen. Wenn ich recht habe, sind die Standardeinstellungen von pgsql das optimistische Locking und das Lesen der Committed-Transaktionsisolation, was bedeutet, dass jede Transaktion die Änderungen anderer nicht festgeschriebener Transaktionen kennt.

In diesem Fall sind diese Einstellungen in Ordnung, so können Sie einfach UPDATE team1 SET score = score + mytotal tun, und die Datenbank wird gut die Nebenläufigkeitsprobleme behandeln.

Wenn Sie eine längere Auswahl haben - Update-Problem, dann können Sie die Zeilen manuell sperren, indem Sie zuerst mit einer SELECT FOR UPDATE Abfrage auswählen.

Diese derzeit die besten Praktiken sind ...