j4nk3y: MySQLi transaction/commit/rollback

Einen wunderschönen zusammen,

Nach langer Zeit der Projektplanung soll es bei mir (eigentlich wieder^^) in die heiße Phase gehen.

Doch ein Problem, wenn man es so sehen möchte, bedarf noch einer Lösung / Erklärung. Da ich, wenn ich den hoffentlich mal fertig werden sollte, von wenigen bis vielen... bis hoffentlich sehr vielen Datenbankzugriffen pro, sagen wir mal, Minuten ausgehe. Bin ich, während meiner vorbereitung, auch über das konstrukt der transaction sowie commit und rollback gestoßen.

Durch

$mysqli->begin_transaction();

werden alle folgenden Datenbankzugriffe zu einer "aktion" zusammengefasst und weitere bzw andere Datenbankzugriffe werden aufgeschoben bis die "aktion" abgeschloßen ist. Bzw die Datenbankverbindung mit

$mysqli->close();

beendet wird.

Sehe ich das richtig? Z.B. auch wenn a.php , b.php aufruft und dort ein

$mysqli->query();

ausgeführt wird und die Datenbankverbindung erst in b.php geschloßen wird?

Bisher ist mir auch noch nicht ganz klar was die Funktionen

$mysqli->commit();
$mysqli->rollback();

veranstalten. Wenn dort jmd eine einfach erklärung hätte, wär ich sehr dankbar.

Zu meiner Sorge:

Sagen wir ich rufe a.php auf und dieses soll meine Datenbank füllen. Je nachdem was ich eingebe "x", läuft eine Schleife "x"-mal durch, welche meine Daten in der Datenbank setzt nach dem Schema:

Daten erzeugen -> DB verbindung aufbauen -> Daten eintragen -> DB verbindung schließen

Dies kann von einigen Sekunden bis mehrere Stunden dauern.

Nun greift ein (mehrere) Benutzer auf meine Webseite zu und fragt Daten ab. Vielleicht wichtig : Nicht aus den Tabellen an den a.php "arbeitet".

Inwieweit können dann probleme auftreten in der abwicklung von a.php und einem script c.php welches vom Benutzer aufgerufen wird.

Ich würde es mir so vorstellen, dass a.php seine Daten erzeugt und falls, während dessen c.php vom Benutzer aufgerufen wird diese Datenbankabfrage durchgeführt wird und wenn diese beendet wurde, a.php solange mit seinem Datenbankzugriff warten muss bis c.php fertig ist.

Ist das korrekt? Wartet a.php bzw c.php auf das fertig werden des jeweils anderen? Oder könnte dort irgendwas übersprungen werden. Und inwieweit sind parallele Ausführungen von Scripten möglich?

Vielen Dank für eure Hilfe!

Mit freundlichem Gruß

Jo

  1. Tach,

    Durch

    $mysqli->begin_transaction();
    

    werden alle folgenden Datenbankzugriffe zu einer "aktion" zusammengefasst und weitere bzw andere Datenbankzugriffe werden aufgeschoben bis die "aktion" abgeschloßen ist.

    nenne das ganze ruhig beim korrekten Namen Transaktion statt "aktion".

    Bzw die Datenbankverbindung mit

    $mysqli->close();
    

    beendet wird.

    Sehe ich das richtig? Z.B. auch wenn a.php , b.php aufruft und dort ein

    $mysqli->query();
    

    ausgeführt wird und die Datenbankverbindung erst in b.php geschloßen wird?

    Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

    Bisher ist mir auch noch nicht ganz klar was die Funktionen

    $mysqli->commit();
    $mysqli->rollback();
    

    veranstalten. Wenn dort jmd eine einfach erklärung hätte, wär ich sehr dankbar.

    Die Transaktion kann mit zwei verschiedenen Zuständen enden, entweder alle innerhalb der Transaktion gemachten Änderungen werden endgültig durchgeführt (commit) oder verworfen (rollback); damit kann man also sicher stellen, dass entweder alle oder keine Änderungen einer Transaktion übernommen werden und der Zustand, die Änderungen an Tabelle 1 sind erledigt aber vor den Änderungen an Tabelle 2 hat das Script abgebrochen, vermeiden.

    Sagen wir ich rufe a.php auf und dieses soll meine Datenbank füllen. Je nachdem was ich eingebe "x", läuft eine Schleife "x"-mal durch, welche meine Daten in der Datenbank setzt nach dem Schema:

    Daten erzeugen -> DB verbindung aufbauen -> Daten eintragen -> DB verbindung schließen

    Dies kann von einigen Sekunden bis mehrere Stunden dauern.

    Nun greift ein (mehrere) Benutzer auf meine Webseite zu und fragt Daten ab. Vielleicht wichtig : Nicht aus den Tabellen an den a.php "arbeitet".

    Dann solltest du keine Probleme bekommen; wie genau dein DBMS (bzw. im Falle von MySQL die verwendete Storage Engine (MyISAM kennt keine Transaktionen)) bei konkurrierenden Transaktionen vorgeht, ist eine Frage der Isolation, damit z.T. Einstellungssache und soltle im Handbuch des DBMS nachlesbar sein. Grob gilt erstmal: Während eine Transaktion läuft, können andere lesende Transaktionen (auch solche, die implizit sind) die geänderten Daten der ersten Transaktion nicht sehen und schreibende Transaktionen müssen warten, bis die erste Transaktion abgeschlossen ist.

    Inwieweit können dann probleme auftreten in der abwicklung von a.php und einem script c.php welches vom Benutzer aufgerufen wird.

    Ich würde es mir so vorstellen, dass a.php seine Daten erzeugt und falls, während dessen c.php vom Benutzer aufgerufen wird diese Datenbankabfrage durchgeführt wird und wenn diese beendet wurde, a.php solange mit seinem Datenbankzugriff warten muss bis c.php fertig ist.

    Ist das korrekt? Wartet a.php bzw c.php auf das fertig werden des jeweils anderen? Oder könnte dort irgendwas übersprungen werden. Und inwieweit sind parallele Ausführungen von Scripten möglich?

    Wenn a.php seine Transaktion vor c.php gestartet hat und beide konkurrierend auf den selben Datenbestand schreiben wollen, dann wird die Transaktion aus c.php praktisch immer warten müssen.

    mfg
    Woodfighter

    1. Tach,

      Durch

      $mysqli->begin_transaction();
      

      werden alle folgenden Datenbankzugriffe zu einer "aktion" zusammengefasst und weitere bzw andere Datenbankzugriffe werden aufgeschoben bis die "aktion" abgeschloßen ist.

      nenne das ganze ruhig beim korrekten Namen Transaktion statt "aktion".

      Ja ich wollte es nur umschreiben, um es anders Auszudrück. Imprinzip um meinen Gedanken zu verdeutlichen.

      Bzw die Datenbankverbindung mit

      $mysqli->close();
      

      beendet wird.

      Sehe ich das richtig? Z.B. auch wenn a.php , b.php aufruft und dort ein

      $mysqli->query();
      

      ausgeführt wird und die Datenbankverbindung erst in b.php geschloßen wird?

      Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

      HM, hier würd ich es gern genau wissen, da ich mir hier unsicher bin. Also bis a.php fertig ist oder bis b.php die Datenverbindung beendet?

      Bisher ist mir auch noch nicht ganz klar was die Funktionen

      $mysqli->commit();
      $mysqli->rollback();
      

      veranstalten. Wenn dort jmd eine einfach erklärung hätte, wär ich sehr dankbar.

      Die Transaktion kann mit zwei verschiedenen Zuständen enden, entweder alle innerhalb der Transaktion gemachten Änderungen werden endgültig durchgeführt (commit) oder verworfen (rollback); damit kann man also sicher stellen, dass entweder alle oder keine Änderungen einer Transaktion übernommen werden und der Zustand, die Änderungen an Tabelle 1 sind erledigt aber vor den Änderungen an Tabelle 2 hat das Script abgebrochen, vermeiden.

      Na das war gut erklärt, Danke. aus dem php Manual hab ich das nicht wirklich heraus gelesen.

      Sagen wir ich rufe a.php auf und dieses soll meine Datenbank füllen. Je nachdem was ich eingebe "x", läuft eine Schleife "x"-mal durch, welche meine Daten in der Datenbank setzt nach dem Schema:

      Daten erzeugen -> DB verbindung aufbauen -> Daten eintragen -> DB verbindung schließen

      Dies kann von einigen Sekunden bis mehrere Stunden dauern.

      Nun greift ein (mehrere) Benutzer auf meine Webseite zu und fragt Daten ab. Vielleicht wichtig : Nicht aus den Tabellen an den a.php "arbeitet".

      Dann solltest du keine Probleme bekommen; wie genau dein DBMS (bzw. im Falle von MySQL die verwendete Storage Engine (MyISAM kennt keine Transaktionen)) bei konkurrierenden Transaktionen vorgeht, ist eine Frage der Isolation, damit z.T. Einstellungssache und soltle im Handbuch des DBMS nachlesbar sein. Grob gilt erstmal: Während eine Transaktion läuft, können andere lesende Transaktionen (auch solche, die implizit sind) die geänderten Daten der ersten Transaktion nicht sehen und schreibende Transaktionen müssen warten, bis die erste Transaktion abgeschlossen ist.

      Ok dann liege ich hier ja richtig, dass ist doch schonmal ganz nice. Ja, das geht "nur" mit der InnoDB, dass weiss ich schon. Mit der Isolation werd ich mich gleich mal schlau lesen, danke.

      Inwieweit können dann probleme auftreten in der abwicklung von a.php und einem script c.php welches vom Benutzer aufgerufen wird.

      Ich würde es mir so vorstellen, dass a.php seine Daten erzeugt und falls, während dessen c.php vom Benutzer aufgerufen wird diese Datenbankabfrage durchgeführt wird und wenn diese beendet wurde, a.php solange mit seinem Datenbankzugriff warten muss bis c.php fertig ist.

      Ist das korrekt? Wartet a.php bzw c.php auf das fertig werden des jeweils anderen? Oder könnte dort irgendwas übersprungen werden. Und inwieweit sind parallele Ausführungen von Scripten möglich?

      Wenn a.php seine Transaktion vor c.php gestartet hat und beide konkurrierend auf den selben Datenbestand schreiben wollen, dann wird die Transaktion aus c.php praktisch immer warten müssen.

      Was ist der selbe Datenbestand? die gleiche Datenbank oder z.b eine gleiche tabelle in der DB?

      mfg
      Woodfighter

      1. Tach,

        Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

        HM, hier würd ich es gern genau wissen, da ich mir hier unsicher bin. Also bis a.php fertig ist oder bis b.php die Datenverbindung beendet?

        die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet. Da dein a.php ja b.php aufruft, kann es allerdings erstmal nicht vor b.php enden, solange du das nicht explizit hervorrufst (und Multthreading ist in PHP immer noch eher selten).

        Transaktion […] commit […] rollback

        Na das war gut erklärt, Danke. aus dem php Manual hab ich das nicht wirklich heraus gelesen.

        Da es hier um Datenbank-Termini geht, ist das PHP-Manual auch eher der falsche Ort zur Erklärung.

        Wenn a.php seine Transaktion vor c.php gestartet hat und beide konkurrierend auf den selben Datenbestand schreiben wollen, dann wird die Transaktion aus c.php praktisch immer warten müssen.

        Was ist der selbe Datenbestand? die gleiche Datenbank oder z.b eine gleiche tabelle in der DB?

        Das kann ich mit einem klaren „Ja“ beantworten. Die dritte Alternative wären übrigens die betroffenen Datensätze in den betroffenen Tabellen. Was exakt für dich zutrifft, findest du beim Stichwort Locking im Handbuch von MySQL.

        mfg
        Woodfighter

        P.S.

        mfg
        Woodfighter

        Bitte beim zitieren, diejenigen Teile, die fürs Verständnis nicht mehr nötig sind, möglichst entfernen

        1. Hey,

          Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

          HM, hier würd ich es gern genau wissen, da ich mir hier unsicher bin. Also bis a.php fertig ist oder bis b.php die Datenverbindung beendet?

          die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet. Da dein a.php ja b.php aufruft, kann es allerdings erstmal nicht vor b.php enden, solange du das nicht explizit hervorrufst (und Multthreading ist in PHP immer noch eher selten).

          Super, Danke!

          Was ist der selbe Datenbestand? die gleiche Datenbank oder z.b eine gleiche tabelle in der DB?

          Das kann ich mit einem klaren „Ja“ beantworten. Die dritte Alternative wären übrigens die betroffenen Datensätze in den betroffenen Tabellen. Was exakt für dich zutrifft, findest du beim Stichwort Locking im Handbuch von MySQL.

          Da setze ich mich gleich mal dran, Danke.

          Gruß

          Jo

          1. Moin!

            Ich bin mit der Erklärung bezüglich der "sich aufrufenden" Skripte nicht zufrieden.

            Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

            HM, hier würd ich es gern genau wissen, da ich mir hier unsicher bin. Also bis a.php fertig ist oder bis b.php die Datenverbindung beendet?

            die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet. Da dein a.php ja b.php aufruft, kann es allerdings erstmal nicht vor b.php enden, solange du das nicht explizit hervorrufst (und Multthreading ist in PHP immer noch eher selten).

            Super, Danke!

            Was kann denn alles "aufrufen" bedeuten? Das, was woodfighter hier meint, ist:

            a.php:
            
            // db-code
            // starte transaktion
            require "b.php"
            
            
            b.php:
            // db-code
            // committe transaktion
            // Skriptende
            

            Was "ruft sich auf" aber auch bedeuten kann:

            a.php:
            
            // db-code
            // starte transaktion
            echo "<a href='b.php'>Klick mich</a>";
            // Skriptende
            
            b.php:
            // Weitermachen mit den Infos vom Linkklicken
            // db-code
            // committe transaktion
            // Skriptende
            

            Anstelle des Links kann man jede andere Aktivität setzen, bei der das Skript A zunächst endet, sein Ergebnis in Form von HTML, Text, Bildern etc. an den Browser sendet, und diesen veranlasst, danach das Skript B aufzurufen.

            Und in diesem Fall ist es mit der Transaktion vorbei, weil die DB-Verbindung mit dem Enden von Skript A geschlossen wird und zum Commit führt.

            Jetzt kann man versuchen, drumherum zu arbeiten. Es gibt da Möglichkeiten. Allerdings haben diese Möglichkeiten auch Nebenwirkungen, über die man sich klarwerden muss.

            Grundsätzlich bedeutet eine laufende Transaktion, dass ein Teil der Daten für den Schreib- oder gar Lesezugriff gesperrt ist. Das kann andere, parallel ablaufende DB-Operationen anhalten. Insofern ist es keine gute Idee, Code zu schreiben, dessen Ausführungszeit unbekannt ist: Skript B könnte irgendwann aufgerufen werden, muss es aber nicht. Wann es aufgerufen wird, ist nicht zu erzwingen, wenn der Aufruf vom Benutzer abhängt.

            Grüße Sven

            1. Nabend,

              Ich bin mit der Erklärung bezüglich der "sich aufrufenden" Skripte nicht zufrieden.

              Ja, solange a.php nicht komplett ausgeführt wird, findet kein implizites Ende der Transaktion statt.

              HM, hier würd ich es gern genau wissen, da ich mir hier unsicher bin. Also bis a.php fertig ist oder bis b.php die Datenverbindung beendet?

              die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet. Da dein a.php ja b.php aufruft, kann es allerdings erstmal nicht vor b.php enden, solange du das nicht explizit hervorrufst (und Multthreading ist in PHP immer noch eher selten).

              Super, Danke!

              Was kann denn alles "aufrufen" bedeuten? Das, was woodfighter hier meint, ist:

              a.php:
              
              // db-code
              // starte transaktion
              require "b.php"
              
              
              b.php:
              // db-code
              // committe transaktion
              // Skriptende
              

              Nein genau so bzw. eine funktion in b.php waas aber das gleiche sein müsste meiner Meinung nach.

              Was "ruft sich auf" aber auch bedeuten kann:

              a.php:
              
              // db-code
              // starte transaktion
              echo "<a href='b.php'>Klick mich</a>";
              // Skriptende
              
              b.php:
              // Weitermachen mit den Infos vom Linkklicken
              // db-code
              // committe transaktion
              // Skriptende
              

              Anstelle des Links kann man jede andere Aktivität setzen, bei der das Skript A zunächst endet, sein Ergebnis in Form von HTML, Text, Bildern etc. an den Browser sendet, und diesen veranlasst, danach das Skript B aufzurufen.

              Wie oben, a.php endet erst wenn b.php fertig ist.

              Und in diesem Fall ist es mit der Transaktion vorbei, weil die DB-Verbindung mit dem Enden von Skript A geschlossen wird und zum Commit führt.

              Ja :) verstanden.

              Jetzt kann man versuchen, drumherum zu arbeiten. Es gibt da Möglichkeiten. Allerdings haben diese Möglichkeiten auch Nebenwirkungen, über die man sich klarwerden muss.

              N drumhgerum arbeiten hab ich früher ml versucht und gemerkt das es unübersichtlich und zu gern zu unfindbren fehlern führen kann, ergo lasse ich das lieber.

              Grundsätzlich bedeutet eine laufende Transaktion, dass ein Teil der Daten für den Schreib- oder gar Lesezugriff gesperrt ist. Das kann andere, parallel ablaufende DB-Operationen anhalten. Insofern ist es keine gute Idee, Code zu schreiben, dessen Ausführungszeit unbekannt ist: Skript B könnte irgendwann aufgerufen werden, muss es aber nicht. Wann es aufgerufen wird, ist nicht zu erzwingen, wenn der Aufruf vom Benutzer abhängt.

              Anhalten bis die transaktion fertig ist.

              Danke

              Gruß

              Jo

            2. Tach,

              Was "ruft sich auf" aber auch bedeuten kann:

              a.php:
              
              // db-code
              // starte transaktion
              echo "<a href='b.php'>Klick mich</a>";
              // Skriptende
              
              b.php:
              // Weitermachen mit den Infos vom Linkklicken
              // db-code
              // committe transaktion
              // Skriptende
              

              ich wäre tatsächlich nicht auf die Idee gekommen, das als Aufrufen zu bezeichnen.

              mfg
              Woodfighter

        2. die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet.

          Es sollte an dieser Stelle erwähnt werden, dass ein Schließen der Datenbankverbindung einem Abbruch der Transaktion, also dem Rollback gleichkommt. Gespeichert wird nur nach ausdrücklichem Commit.

          1. Nabend,

            die Transaktion endet bei den folgenden Vorkomnissen: Explizit durch Commit oder Rollback, Implizit durch Ende der Datenbankverbindung, letzteres passiert IIRC in PHP ebenfalls implizit, wenn das Script, das die Verbindung geöffnet hat, endet.

            Es sollte an dieser Stelle erwähnt werden, dass ein Schließen der Datenbankverbindung einem Abbruch der Transaktion, also dem Rollback gleichkommt. Gespeichert wird nur nach ausdrücklichem Commit.

            Top, so habe ich es auch verstanden, also speichern nur bei commit(), nicht speichern bei close() und rollback(), in jedemfall plus script ende, beenden der transaction.

            Gruß

            Jo

    2. Hey,

      Dann solltest du keine Probleme bekommen; wie genau dein DBMS (bzw. im Falle von MySQL die verwendete Storage Engine (MyISAM kennt keine Transaktionen)) bei konkurrierenden Transaktionen vorgeht, ist eine Frage der Isolation, damit z.T. Einstellungssache und soltle im Handbuch des DBMS nachlesbar sein. Grob gilt erstmal: Während eine Transaktion läuft, können andere lesende Transaktionen (auch solche, die implizit sind) die geänderten Daten der ersten Transaktion nicht sehen und schreibende Transaktionen müssen warten, bis die erste Transaktion abgeschlossen ist.

      So, nach einem gründlichem Überflug des wiki-Artikels bin ich schon wieder ultra verwirrt.

      Nachdem lesen scheint es mir wieder so, als ob Transaktionen gleichzeitig ablaufen können, sonst würden ja keine Dirty reads, Non-repeatable reads oder phantom reads auftreten können wenn Transaktionen nur nacheinander ausgeführt werden können.

      Gruß

      Jo