PHP und Nebenläufigkeit

7

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

Obwohl ich grundlegendes SQL kenne und mit der grundlegenden Manipulation von Daten in einer Datenbank gearbeitet habe, verstehe ich nicht, wie Webentwickler, die ihre Websites um PHP / Javascript / SQL aufbauen, Benutzer verwalten können, die dieselben Daten gleichzeitig ändern Zeit.

Nehmen wir zum Beispiel an, Sie haben eine Blackjack-Website, die Nutzer in zwei Teams aufteilt, 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 hinzugefügt.

Nehmen wir an, der Pseudocode für die Funktion, die das tut, sieht ungefähr so ​​aus:

%Vor%

Wenn zwei Spieler gleichzeitig spielen, ist es sehr wahrscheinlich, dass beide SELECT aufrufen, bevor der andere die Möglichkeit hat, die Tabelle zu erhöhen 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 getan, oder gibt es Funktionen, die von der Datenbank zur Verfügung gestellt werden, die Sie verwenden, um dies zu verhindern?

Ich habe einige Nachforschungen angestellt, und es scheint, dass PHP einen Semaphor -Mechanismus bietet, und ich habe es auch bemerkt dass mysql eine Funktion LOCK-Tabelle anbietet. Ich bin mir jedoch nicht sicher, welche davon, wenn auch, in der Praxis verwendet wird.

    
Zachary Wright 11.11.2009, 03:40
quelle

7 Antworten

5

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

    
Byron Whitlock 11.11.2009, 03:55
quelle
11

Behalte die Logik bei der DB, diese Semantik wurde meistens für dich gelöst.

%Vor%

.. oder welche Punktzahl und welche Teamnummer auch immer.

    
Jé Queue 11.11.2009 03:45
quelle
4

Wichtige 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 wird jede Aktualisierungsanforderung für dieselbe Zeile warten, 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.

    
Nirmal 11.11.2009 03:56
quelle
2

Ich stimme der Antwort von Xepochs zu, führe keine Nebenläufigkeitsprobleme ein, es sei denn, du musst es unbedingt tun. Für eine gute Antwort zu verschiedenen Sperrstrategien siehe hier .

    
deceze 11.11.2009 03:55
quelle
1

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

In den meisten Fällen sind Ä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 Funktion mysql_query() gibt FALSE zurück, wenn ein Problem vorliegt.

Dann können Sie die Ursache ermitteln (Aktualisierungskonflikt, unzureichende Berechtigungen, SQL-Syntaxfehler usw.), indem Sie mysql_errno() aufrufen. Siehe Ссылка für die MySQL-Fehlercode-Referenz.

    
Bill Karwin 11.11.2009 03:54
quelle
1

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

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 an der Zeit, Ihr Design zu überdenken. Warum behalten Sie keine Nutzer-ID für jeden, der einen Teil ihrer Gewinne hinzugefügt hat? Sie könnten dann ein:

haben %Vor%

Aber wenn ich es wäre, würde ich mich nicht einmal darum kümmern. 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, das jQuery-Framework für asynchrone Client-Server-Kommunikation zu betrachten, da dies der einfachste Weg ist, dies zu erreichen.

BEARBEITEN: Und für das Problem der Aktualisierung der Benutzeroberfläche jedes Spielers, wenn ein anderer Spieler einen Betrag zur Punktzahl hinzufügt, schlage ich vor, dass Sie in backbone.js schauen, was Ihr Datenmodell schön auf den Client des Spielers passt dass sie sofort aktualisiert werden, wenn sich der Score ändert.

    
snez 19.11.2011 23:44
quelle
0

Datenbanken verfügen über eine integrierte Steuerung des gemeinsamen Zugriffs, zum Beispiel können Sie hier 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 Ihrem Fall sind diese Einstellungen in Ordnung, Sie können also einfach UPDATE team1 SET score = score + mytotal verwenden, und die Datenbank wird die Probleme mit der Parallelität gut 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.

Dies sind derzeit die besten Praktiken ...

    
inf3rno 06.04.2014 17:30
quelle

Tags und Links