Datensatz vor Änderungen während Bearbeitung schüt

Hallo, liebe Experten!

Ich habe eine Auftragsverwaltung in MySQL. Wenn Client A nun einen Datensatz ausliest und bearbeitet in PHP, dies evtl. jedoch ne Weile dauert, kann es ja sein, daß sich inzwischen ein Client B über den Datensatz hermacht und diesen ändert. Wenn Client A dann seine Änderungen speichert, werden die neueren Daten aber wieder mit den alten Daten überschrieben. Wie kann ich dies überwachen und z.B. abfangen, um dem langsameren Client A mitzuteilen, das inzwischen eine Änderung stattgefunden hat und er zuerst den Datensatz neu Aufrufen soll und seine Änderungen wiederholen?

Bin dankbar für jeden Tipp oder jede Buchempfehlung.

Gruß
Rantanplan

Hi -

Ich habe eine Auftragsverwaltung in MySQL. Wenn Client A nun
einen Datensatz ausliest und bearbeitet in PHP, dies evtl.
jedoch ne Weile dauert, kann es ja sein, daß sich inzwischen
ein Client B über den Datensatz hermacht und diesen ändert.

Das ist das klassische Problem eines „dirty reads“ - Das Themengebiet dieser Problematik heißt Transaktionssicherheit. Es gibt hier mehrere mögliche Lösungen, die jeweils mehr oder weniger Benutzer- bzw. Performancefreundlich sind.

Einen Einstiegsartikel (bzgl. MySql) habe ich auf die schnelle hier gefunden: http://www.linux-magazin.de/Artikel/ausgabe/2001/08/…

Ein Lock der Tabelle während der gesamten Transaktion (holen des Datensatzes, editieren, zurückschreiben), ist natürlich nicht praktikabel - Während der Zeit kann kein anderer auf die Tabelle zugreifen und muß warten bzw. läuft in einen Timeout.

Eine mögliche Lösung wäre diese:

Du ergänzt die fragliche Tabelle um ein TIMESTAMP Feld - Dieses wird von MySql jedesmal auf die aktuelle Systemzeit geupdatet, wenn der Datensatz geschrieben (insert, update) wird.

Jeder Client darf jederzeit einen Datensatz holen.

Wenn ein Client allerdings einen editierten Datensatz speichern möchte, muß er das folgende tun:

  • Tabelle locken (Siehe Artikel)

  • Den Datensatz nochmals holen

  • Die Timestamps der beiden Datensätze vergleichen

  • Die Änderung nur dann schreiben, wenn die Timestamps übereinstimmen

  • Tabelle wieder freigeben

Wie du im Artikel lesen kannst, ist dies eine Transaktion - Du mußt auf jeden Fall sicherstellen, dass jede Anweisung durchlaufen wird - Sonst kannst du eine Menge Probleme bekommen. Wenn sich dein Code zB. beim nochmaligen holen des Datensatzes aufhängt, mußt du zB. unbedingt dafür sorgen, dass die Tabelle wieder freigegeben wird - Sonst hast du einen kapitalen Datenbankaussetzer.

Falls die Timestamps nicht übereinstimmen sollten (Dh. Ein anderer Client hat den Datensatz in der Zwischenzeit geändert), kann man mehrere Strategien fahren:

zB.:

  • Wer zuerst kommt, mahlt zuerst: Fehlermeldung, dass der Datensatz ncht geschrieben werden kann

  • Vergleichen, welche Attribute des Datensatzes verändert wurden - Wenn es keine Überschneidungen gibt, den geholten und den editierten Datensatz mergen und ungefragt in die Datenbank schreiben. VORSICHT: Das geht natürlich nicht immer - Es kommt auf den Datensatz an.

  • Datenbank unlocken und dem Client beide Datensätze präsentieren - Er soll dann beide abgleichen

  • usw.

mfG,

J.P.Jarolim

Hallo, J.P.!
Danke, das hilft mir schon wesentlich. Hatte gehofft, daß es einfacher geht. Schönen Dank auch für die ausführliche Beschreibung.
Gruß
Rantanplan

einfacher geht auch…
Hi Rantanplan (grüss Luke von mir ^^)

Einfacher geht es natürlich auch…

Wenn Du einfach eine Spalte mit einem Versionsindex versiehst und diesen dann hochziehst, dann reicht Dir ein einfaches statement…

Beispiel:
Tabelle:
id (int auto_increment)
Text (text)
version (int)

wenn Du den Datensatz zum editieren abholst holst Du alles - id, version und text - wenn es dann fertig ist machst Du ein einfaches update

mysql_query(„UPDATE $tabelle SET Text=’$neuertext’, version=version+1 WHERE id=’$_POST[id]’ AND varion=’$_POST[version]’“);

sollte nun jemand anderes die letzte Version geändert haben, dann stimmt die Versionierung nicht mehr - das SQL Statement läuft ins leere.

Anschliessend kannst du mit den affected_rows rausfinden ob das Update einen Datensatz geändert hat - wenn es 1 ist - alles wunderbar, wenn es 0 ist dann kannst Du die Daten neu abholen und eine warnung ausgeben - am besten gibst Du dann nochmal beide Möglichkeiten aus - die übermittelte und die aus der Datenbank…

Grüsse
Munich