# Nebenläufigkeit mit Php und SQL ein Problem?



## CL90 (8. November 2015)

*Nebenläufigkeit mit Php und SQL ein Problem?*

Moin!

Ich habe eine vermutlich blöde Frage:
Existiert ein Problem der Nebenläufigkeit auf einem Webserver der php und Mysql benutzt?

ELO Bewertungsystem:
Die Score von 2 Personen wird über SQL abgerufen und neu berechnet. 
Ein anderer Nutzer aktualisiert in genau diesem Momment die ELO einer der beiden Personen.

Wie darf ich mir die Aufrufreihenfolge vorstellen?
Wird nach Prinzip "first-come-first-serve" der erste Nutzer vollständig versorgt, oder werden zwischendurch noch andere benutzer reingeschoben? (via multifthread oder so)


----------



## DarkMo (8. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

das hat mE mit php rein garnichts zu tun, sondern ist ganz allein sache der DB. genau diese muss für die vollständigkeit von transaktionen sorge tragen. Tritt ein fehler bei einer transaktion auf, so muss sie den ursprünglichen zustand wiederherstellen, wollen mehrere gleichzeitig was wissen, so muss sie dafür sorge tragen, dass das alles korrekt abläuft. sprich: die einzelnen clienten schicken ihre anfragen, diese werden auf dem server bearbeitet und per sql-anweisung der DB übergeben. dort geschieht dann genau das, worüber du dir sorgen machst ^^


----------



## CL90 (8. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

Das hilft mir jetzt leider nicht weiter.
Mir ist klar das die MySQL db selbstsändig das korrekte abhandeln von Queries regelt.
Die frage ist nur ob mir das php dazwischen funkt und DB-technisch korrekte Queries callt die den DB kontent aber verhunzen.

Beispiel: (Nebenläufige Abfrage)
UserA: Request Data012
UserB: Request Data012, 
UserB: Work with Data012
UserB: Update Data012 to DB
UserA: Work with Data012
UserA: Update Data012 to DB.

Was UserB hier berechnet hat wird verworfen wenn der Server nicht first-come-first-serve arbeitet.


----------



## DarkMo (8. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

achso, wenn die clients "gleichzeitig" daten holen aber versetzt wieder speichern... hmm, dann wird wohl überschirben und man verliert die daten von a. da könnte man versuchen mit zeiten zu arbeiten. also userA speichert die letzte Bearbeitungs-Zeit, UserB auch. da beide erstmal nur lesen und nicht schreiben, erhalten sie die gleiche Zeit. beim schreiben ihrer daten ändern sie auch genau diese zeitvariable gleich mit (auf "now"). vorm schreiben erfolgt dann natürlich die prüfung ob die zeit noch stimmt bzw noch besser wird das direkt in der sql-qry geprüft (update <bla> where id = id and last_change = my_last_change_copy -- pseudocode mäßig).

das kann aber auch ziemlich in die hose gehen bei "hoch frequentierten" seiten *grübel* ist dann wie lotto spielen, dass man den kram aktualisieren darf ^^


----------



## CL90 (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

Die Clienten erhalten die Daten eigentlich nicht.
das Problem kann nur auftretten, wenn der Php Code, der auf dem Server ausgeführt wird, durch einen anderen User unterbrochen werden kann.
Wenn der Server Jedes request nacheinander abhandelt macht UserA erst fertig, und dann zieht B die korrekten Daten.

Alles was ich wissen muss ist, ob ein phpServer soetwas wie Interrupts hat.


----------



## MaxRink (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

nein hat er nicht. Es lässt sich allerdings mit Erweiterungen und / oder den richtigen Frameworks realisieren.


----------



## CL90 (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*



MaxRink schrieb:


> nein hat er nicht. Es lässt sich allerdings mit Erweiterungen und / oder den richtigen Frameworks realisieren.



Top 
Weil Interrupts möchte ich nicht haben 
Dann wird die ELO also in jeder situation richtig berechnet und es gehen keine UpdateQueries verlohren.

Danke euch


----------



## DarkMo (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

ah, also wird ein php skript vom server in einem rutsch abgearbeitet und ein weiterer client wird erst danach abgefertigt? oder versteh ich das gerade falsch? ^^ ist jedenfalls interessant zu wissen.


----------



## Ap0ll0XT (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*



DarkMo schrieb:


> ah, also wird ein php skript vom server in einem rutsch abgearbeitet und ein weiterer client wird erst danach abgefertigt? oder versteh ich das gerade falsch? ^^ ist jedenfalls interessant zu wissen.


Das kommt ganz auf die Server-Konfiguration an und wie PHP eingehängt wird. Zum Beispiel kann NGINX mit seinen Workerthreads PHP auch von mehreren Clients simultan ausführen lassen. Allerdings arbeitet die Datenbank die Datensätze nach der Reihenfolge der Queries ab. Macht also Client A ein Update Query auf Datensatz X in Tabelle Y, dann wird auch dieses Update zuerst komplett verarbeitet und erst dann erfolgt der nächste Update Query auf den selben Datensatz. Das bedeutet also, das in der Datenbank die einzelnen Datensätze sicher gespeichert werden.

Was allerdings die Datenbank nicht macht ist prüfen, welcher Client einen Datensatz zuerst zur Bearbeitung geöffnet hat. Darum muss man sich dann selbst im Skript kümmern. Da kann man zum Beispiel ein ähnliches Prinzip wie bei einem Mutex in der Multithread-Programmierung einsetzen. Eine weitere Spalte für die Tabelle, in der die USER-ID des Clients gespeichert wird, der gerade den Datensatz bearbeitet. Ist er fertig, wird per Update die ID direkt entfernt und steht für den nächsten Client wieder frei zur Verfügung.

*Kleiner Tipp:* Wenn du versuchst, einen Zahlenwert relativ mit einer bestimmten Zahl zu bearbeiten (z.B. Wert-Der-Spalte + X), tue das am besten über den Query in SQL und nicht über PHP. Denn wenn du zuerst die Zahl aus der Datenbank liest und erst dann in PHP bearbeitest, kann beim speichern eine Aktualisierung des Wertes durch einen anderen Client schon wieder den Ausgangswert verändert haben. Und dann stimmen die Zahlen nicht.

Ich habe den ganzen Spaß gerade mit FastCGI und Multithread durch. Echt spannend und es ist interessant, wie schnell eine Webanwendung rennt, wenn kein PHP dazwischen ist und alle Variablen, Arrays und Co. typsicher sind. Da merkt man erst, wie Sch**** PHP eigentlich ist


----------



## CL90 (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*



Ap0ll0XT schrieb:


> *Kleiner Tipp:* Wenn du versuchst, einen Zahlenwert relativ mit einer bestimmten Zahl zu bearbeiten (z.B. Wert-Der-Spalte + X), tue das am besten über den Query in SQL und nicht über PHP. Denn wenn du zuerst die Zahl aus der Datenbank liest und erst dann in PHP bearbeitest, kann beim speichern eine Aktualisierung des Wertes durch einen anderen Client schon wieder den Ausgangswert verändert haben. Und dann stimmen die Zahlen nicht.


Also doch eine schwachstelle, wenn der Server Multithreaded arbeitet.

Okay. aber kann man auch "komplexere" berechnungen als Query durchjagen?

Das ist der Code der an einem Stück als Query ausgefürt werden müsste:

```
$QWinner            = mysql_query("SELECT ID, votes, score FROM mashobjects WHERE id = $vote");
            $QLooser            = mysql_query("SELECT ID, votes, score FROM mashobjects WHERE id = $vID");

            if(mysql_num_rows($QWinner) == 1 && mysql_num_rows($QLooser) == 1) {
                $AWinner         = mysql_fetch_row($QWinner);
                $ALooser        = mysql_fetch_row($QLooser);

                $Ea                = 1 / (1 + 10^( ($ALooser[2] - $AWinner[2]) / 400) );
                $Eb                = 1 / (1 + 10^( ($AWinner[2] - $ALooser[2]) / 400) );

                $Ra             = $AWinner[2] + $ConvFactorK * (1 - $Ea);
                $Rb                = $ALooser[2] + $ConvFactorK * (0 - $Ea);

                $VotesA            = $AWinner[1] + 1;
                $VotesB         = $ALooser[1] + 1;

                mysql_query("UPDATE mashobjects SET votes = $VotesA, score = $Ra WHERE ID = $AWinner[0]");
                mysql_query("UPDATE mashobjects SET votes = $VotesB, score = $Rb WHERE ID = $ALooser[0]");

            }
```


----------



## Ap0ll0XT (9. November 2015)

*AW: Nebenläufigkeit mit Php und SQL ein Problem?*

Also erstens ist die MySQL-Bibliothek in PHP deprecated. Nutze bitte entweder MySQLi oder PDO.

Du kannst auch mit 3 Queries arbeiten und dann mit hilfe eines Locks (wie bei einem Mutex) die Bearbeitung durch andere verhindern. Das Skript setzt also per Update die User-ID in der entsprechenden Spalte, lädt per Select den Datensatz und du kannst die Berechnungen durchführen. Danach schreibt das Skript mit einem Update Query die Daten wieder hinnein und entfernt die User-ID. Das Skript arbeitet dabei unter 100 Millisekunden. Wenn also ein weiterer Nutzer das ganze bearbeiten will, muss er eben warten, bis der Datensatz frei ist. Da kannst du eine Schleife nehmen, die dann 500 ms pro Durchlauf wartet und jedes mal prüft, ob eine User-ID drin steht. Wenn nicht, geht es aus der Schleife und der nächste kann bearbeiten. Dazu eignen sich vor allem Prepared Statements zu, was ich übrigens auch empfehlen würde.

Du könntest theoretisch auch eine Stored Procedure und eine SQL-Seitige Warteschleife nutzen. Dadurch wird der Datenbank-Server nicht ständig mit Anfragen torpediert. Aber als einfache Lösung wäre der Mutex und Abfrage in PHP.

Aber so wie ich das sehe stehen die Datensätze ja in einer Tabelle und wenn du mit Sicherheit einschließen kannst, das es am Ende auch wirklich nur bestimmte Datensätze gibt, dann sollte das Möglich sein. Aber der Query wird auf jeden Fall sehr komplex.

Ob Transaktionen mit ihren Sperren helfen können, weiß ich gerade nicht wirklich. Allerdings kommt mir das nicht logisch bei zustandsloser Abarbeitung vor. Bei Anwendungen, die eine Transaktion permanent offen halten können, kann PHP das natürlich nicht. Transaktionen sind gerade in PHP so Dinge, die für mich eh schwer begreifbar sind. Man kann zwar bei mehreren Queries in einem Skript (Aufruf) die Konsistenz schützen. Aber über mehrere Queries und bei mehreren Nutzern konnte ich bisher nicht so ganz verstehen, was es bringen soll. Vielleicht kann das dann jemand anderes erklären.


----------

