Claudia 1982: Transaktion mit PHP5 und MySQL

Hallo zusammen,

ich weiß noch nicht wie folgende Situation realisiere... Vielleicht könnt ihr mir weiterhelfen.

Ich lese Daten per mysqli aus meiner Datenbank. Ein Select auf einen Datensatz. Jetzt kann der Anwender diesen Datensatz bearbeiten und dann speichern.

Alles kein Problem....

Wenn aber ein zweiter Anwender parallel den Datensatz einließt, bevor der erste den Datensatz speichert und dann die Daten speichert, bekommt der erste Anwender nicht die Änderung des zweiten Anwenders mit. Speichert der Erste nun, überschreibt dieser wieder die Änderungen des zweiten Anwenders, ohne jemals die Änderung des Zweiten mitbekommen, gesehen zu haben...

Mein Idee ist es den Datensatz zu sperren, wenn jemand diesen ließt und beim Speichern wieder freizugeben, wenn dieser gespeichert wird. Wie kann ich dies technisch lösen?

Danke

  1. Hallo,

    Wenn aber ein zweiter Anwender parallel den Datensatz einließt, bevor der erste den Datensatz speichert und dann die Daten speichert, bekommt der erste Anwender nicht die Änderung des zweiten Anwenders mit. Speichert der Erste nun, überschreibt dieser wieder die Änderungen des zweiten Anwenders, ohne jemals die Änderung des Zweiten mitbekommen, gesehen zu haben...

    Mein Idee ist es den Datensatz zu sperren, wenn jemand diesen ließt und beim Speichern wieder freizugeben, wenn dieser gespeichert wird. Wie kann ich dies technisch lösen?

    das von Dir vorgesehene Vorgehen nennt man pessimistisches Sperren und ist gerade im Webumfeld *NICHT* ratsam.

    Im Handbuchkapitel [http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html@title=MySQL Transactional and Locking Statements] findest Du, was MySQL hinsichtlich Transaktionen und Sperren kann.

    Ich empfehle Dir, eine Spalte (TIMESTAMP) mitzuführen, in der der Zeitpunkt der letzten Änderung gespeichert wird. Versieh das Update-Statement nicht nur mit dem Primärschlüssel in der WHERE-Klausel, sondern mit dem kompletten Datensatz. Wurde kein Datensatz geändert, so wurde der Datensatz in der Zwischenzeit geändert und Du kannst den Benutzer eine entsprechende Mitteilung geben:

    "Der Datensatz wurde in der Zwischenzeit geändert,
       die neuen Angaben sind wie folgt:

    [...]

    Wollen Sie diesen Datensatz mit Ihren Änderungen überschreiben?"

    Freundliche Grüße

    Vinzenz

  2. Mein Idee ist es den Datensatz zu sperren, wenn jemand diesen ließt und beim Speichern wieder freizugeben, wenn dieser gespeichert wird. Wie kann ich dies technisch lösen?

    Hallo,

    vielleicht hilft Dir LOCK TABLE weiter ..

    MfG
    cross

    1. Hello,

      vielleicht hilft Dir LOCK TABLE weiter ..

      Nein LOCK Table sollte hier nicht weiterhelfen, da Das LOCK beim Ende der Verbindung automatisch wieder gelöst wird. Anderenfalls würden sich "lost Locks" ansammeln...

      Liebe Grüße aus Syburg bei Dortmund

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Nein LOCK Table sollte hier nicht weiterhelfen, da Das LOCK beim Ende der Verbindung automatisch wieder gelöst wird. Anderenfalls würden sich "lost Locks" ansammeln...

        Das können/müssen sie doch auch, oder nicht?! Wichtig ist doch imho nur, dass sie AM ENDE der Verbindung aufgelöst werden und nicht dann, wenn jemand gleichzeitig schreiben möchte.

        Liebe Grüße aus Syburg bei Dortmund

        Ein nettes HUHU aus Letmathe in die Nachbarschaft :)

        1. echo $begrüßung;

          » Nein LOCK Table sollte hier nicht weiterhelfen, da Das LOCK beim Ende der Verbindung automatisch wieder gelöst wird. Anderenfalls würden sich "lost Locks" ansammeln...
          Das können/müssen sie doch auch, oder nicht?! Wichtig ist doch imho nur, dass sie AM ENDE der Verbindung aufgelöst werden und nicht dann, wenn jemand gleichzeitig schreiben möchte.

          Der vom OP beschriebene Vorgang zieht sich über mindestens zwei Roundtrips hinweg, die Verbindung wird jedoch bei jedem einzelnen Roundtrip neu aufgebaut und wieder beendet.

          1. Daten aus DB holen und zur Bearbeitung mittels eines Formulars darstellen.
          2. Daten entgegennehmen und in DB schreiben, gegebenenfalls aber eine Affenformularrunde einlegen.

          echo "$verabschiedung $name";

  3. echo $begrüßung;

    Wenn aber ein zweiter Anwender parallel den Datensatz einließt, bevor der erste den Datensatz speichert und dann die Daten speichert, bekommt der erste Anwender nicht die Änderung des zweiten Anwenders mit. Speichert der Erste nun, überschreibt dieser wieder die Änderungen des zweiten Anwenders, ohne jemals die Änderung des Zweiten mitbekommen, gesehen zu haben...
    Mein Idee ist es den Datensatz zu sperren, wenn jemand diesen ließt und beim Speichern wieder freizugeben, wenn dieser gespeichert wird. Wie kann ich dies technisch lösen?

    Eine Sperre wäre durch das manuelle Setzen eines Flags möglich. Die im DBMS vorhandenen Möglichkeiten zum Sperren sind für das Szenario nicht verwendbar, weil sie am Verbindungsende, was spätestens mit dem Script-Ende zusammenfällt, aufgelöst werden. Ein gravierender Nachteil des manuellen Flags ist seine eventuell nicht stattfindende Rücksetzung, weil der Bearbeiter einfach die Bearbeitung abbricht, ohne dass der Webserver etwas davon mitbekommt, oder weil er einfach vergessen hat, die Bearbeitung zu beenden.

    Eine weitere (und vermutlich beste mit dem wenigsten Aufwand im Normalfall) Möglichkeit ist, einen Timestamp für ein "zuletzt bearbeitet am/um" mitzuführen. Jeder Update wird um eine Bedingung erweitert, die den Updaten nur dann ausführt, wenn der Timestamp beim Lesen mit dem aktuellen Timestamp im Datensatz übereinstimmt. Ergibt das Ergebnis der Query-Funktion, dass kein Datensatz geändert wurde, liegt das dann daran, dass entweder der Datensatz gelöscht wurde oder verändert wurde und sich damit der Timestamp geändert hat.
    Je nach Anwendungsfall kann ein Timestamp schon zu grob sein, da er nur sekundengenau ist. In dem Fall kann man einen anderen eindeutige(re)n Wert verwenden, beispielsweise einen UUID.

    echo "$verabschiedung $name";

  4. Hello,

    hierfür muss das Design der Tabelle angepasst werden.
    Ein Conflict-Counter (Schreibzähler), der mit jedem Schreibvorgang um eins heraufgesetzt wird.
    Der Schreibvorgang wird nur zugelassen, wenn der im Datensatz in der Tabelle befindliche Zählerwert noch mit dem im Bearbeitungspuffer (in der der Session) befindlichen übereinstimmt.

    Diese Aufgabe ist ein sehr gutes Anwedungsbeispiel für eine Stored Procedure.
    Wenn man dann zum Update immer diese Stored Procedure einsetzt, kann man nicht vergessen, die Prüfung vorzunehmen.

    Liebe Grüße aus Syburg bei Dortmund

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de