Warum Transaktionen erforderlich sind

Bei der Arbeit mit einer Datenbank kommt es sehr oft vor, dass viele verschiedene Aktionen ausgeführt werden müssen, diese aber nur zusammen sinnvoll sind.

Wir schreiben zum Beispiel eine Bankensoftware, die drei Dinge tun soll:

  • Geld vom Konto des Kunden abheben
  • Fügen Sie Geld dem Konto des Empfängers hinzu
  • Erfassen Sie die Buchungsdaten im „Buchungsprotokoll“

Tritt bei der Ausführung einer dieser Aktionen ein Fehler auf, müssen auch die anderen beiden abgebrochen werden. Es ist unmöglich, Geld vom Kunden abzuschreiben und es nicht dem Empfänger hinzuzufügen? Nun, oder dem Empfänger hinzufügen, aber nicht vom Kunden abschreiben?

Eine solche logische Gruppierung verschiedener Aktionen zu einer wird daher als Transaktion bezeichnet . Mit anderen Worten: Eine Transaktion ist eine Gruppe von Aktionen, die nur alle zusammen ausgeführt werden dürfen . Wenn eine Aktion fehlgeschlagen ist oder mit einem Fehler ausgeführt wurde, müssen alle anderen Aktionen abgebrochen werden.

Eine Transaktion hat normalerweise drei Zustände:

  • Ausgangszustand – der Zustand des Systems vor der Ausführung einer Gruppe von Aktionen
  • Erfolgsstatus – Status nach Abschluss der Aktionsgruppe
  • gescheiterter Zustand – etwas ist schief gelaufen

In diesem Fall gibt es normalerweise drei Befehle:

  • begin/start – wird vor dem Start der logischen Aktionsgruppe ausgeführt
  • commit – wird nach der Transaktionsaktionsgruppe ausgeführt
  • Rollback – startet den Prozess der Rückkehr des Systems vom ausgefallenen Zustand in den Ausgangszustand

Es funktioniert so.

Zuerst müssen Sie eine Transaktion öffnen – rufen Sie die Methode begin() oder start() auf . Der Aufruf dieser Methode gibt den Zustand des Systems an, zu dem wir zurückkehren wollen, wenn etwas schief geht.

Anschließend werden alle Aktionen ausgeführt, die zu einer logischen Gruppe – einer Transaktion – zusammengefasst werden.

Dann wird die Methode commit() aufgerufen . Sein Aufruf markiert das Ende einer logischen Gruppe von Aktionen und leitet in der Regel auch den Prozess der Umsetzung dieser Aktionen in die Praxis ein.

Erinnern Sie sich daran, wie wir etwas in FileWriter geschrieben haben: Zuerst wird alles, was wir geschrieben haben, im Speicher gespeichert, und wenn dann die Methode „flush()“ aufgerufen wird , werden alle Daten aus dem Puffer im Speicher auf die Festplatte geschrieben. Dieses Flush() ist das Transaktions-Commit.

Nun, wenn während des Transaktionsvorgangs ein Fehler aufgetreten ist, müssen Sie den Prozess der Rückkehr in den Ausgangszustand einleiten. Dieser Vorgang wird rollback() genannt und normalerweise ist dafür die gleichnamige Methode verantwortlich.

Grob gesagt gibt es zwei Möglichkeiten, eine Transaktion abzuschließen:

  • COMMIT – wir bestätigen alle vorgenommenen Änderungen
  • ROLLBACK – alle vorgenommenen Änderungen rückgängig machen

Transaktionen in JDBC

Fast jedes DBMS kann mit Transaktionen arbeiten. Daher unterstützt JDBC auch diesen Fall. Alles ist sehr einfach umgesetzt.

Zunächst wird jeder Aufruf der Methodeexecute() des Statement-Objekts in einer separaten Transaktion ausgeführt. Zu diesem Zweck verfügt Connection über einen AutoCommit- Parameter . Wenn es auf „true“ gesetzt ist , wird commit() nach jedem Aufruf der Methode „execute()“ aufgerufen .

Zweitens: Wenn Sie mehrere Befehle in einer Transaktion ausführen möchten, können Sie dies folgendermaßen tun:

  • Deaktivieren Sie AutoCommit
  • Rufen Sie unsere Teams an
  • Rufen Sie die Methode commit() explizit auf

Es sieht ganz einfach aus:

connection.setAutoCommit(false);

Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");

connection.commit();

Tritt während der Ausführung der commit()- Methode ein Fehler auf dem Server auf , bricht der SQL-Server alle drei Aktionen ab.

Aber es gibt Situationen, in denen der Fehler immer noch auf der Clientseite auftritt und wir nie zum Aufruf der commit()- Methode gelangt sind :

connection.setAutoCommit(false);

Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");

connection.commit();

Wenn während der Ausführung einesexecuteUpdate() ein Fehler auftritt , wird die commit()- Methode nicht aufgerufen. Um alle durchgeführten Aktionen rückgängig zu machen, müssen Sie die Methode rollback() aufrufen . Normalerweise sieht es so aus:

try{
  	connection.setAutoCommit(false);

  	Statement statement = connection.createStatement();
  	int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

Speicherpunkte

Mit der Einführung von JDBC 3.0 wurde es möglich, mit dem Transaktions-Rollback effizienter zu arbeiten. Jetzt können Sie Speicherpunkte festlegen – Speicherpunkte, und wenn Sie die Operation rollback() aufrufen , ein Rollback zu einem bestimmten Speicherpunkt durchführen.

Zum Speichern müssen Sie einen Sicherungspunkt erstellen, dies geschieht mit dem Befehl:

Savepoint save = connection.setSavepoint();

Das Zurücksetzen auf einen Sicherungspunkt erfolgt mit dem folgenden Befehl:

connection.rollback(save);

Versuchen wir, vor unserem problematischen Befehl einen Sicherungspunkt hinzuzufügen:

try{
  	connection.setAutoCommit(false);

  	Statement statement = connection.createStatement();
  	int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");

  	Savepoint save = connection.setSavepoint();
 	 try{
      	int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");
 	 }
 	 catch (Exception e) {
    	   connection.rollback(save);
 	 }

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

Wir haben verschachtelte Transaktionen organisiert, indem wir vor dem Aufruf der problematischen Methode einen Speicherpunkt hinzugefügt haben und durch Aufrufen der Methode rollback(save) zum gespeicherten Zustand zurückgekehrt sind .

Ja, es ist dem Speichern/Laden in Spielen sehr ähnlich.