Waarom transacties nodig zijn

Heel vaak doet zich bij het werken met een database een situatie voor waarin u veel verschillende acties moet uitvoeren, maar ze hebben alleen zin samen.

We schrijven bijvoorbeeld banksoftware die drie dingen moet doen:

  • Geld opnemen van de rekening van de klant
  • Geld toevoegen aan de rekening van de ontvanger
  • Leg de boekingsgegevens vast in het "postingslogboek"

Als er een fout optreedt tijdens de uitvoering van een van deze acties, moeten de andere twee ook worden geannuleerd. Het is onmogelijk om geld van de klant af te schrijven en niet toe te voegen aan de ontvanger? Welnu, of toevoegen aan de ontvanger, maar niet afschrijven van de klant?

Zo'n logische groepering van verschillende acties tot één wordt dus een transactie genoemd . Met andere woorden, een transactie is een groep acties die alleen samen moeten worden uitgevoerd . Als een actie is mislukt of met een fout is uitgevoerd, moeten alle andere acties worden geannuleerd.

Een transactie heeft meestal drie statussen:

  • beginstatus - de status van het systeem voordat een groep acties wordt uitgevoerd
  • successtatus - status nadat de actiegroep is voltooid
  • mislukte toestand - er is iets misgegaan

In dit geval zijn er meestal drie commando's:

  • begin/start - uitgevoerd vóór de start van de logische groep acties
  • commit - uitgevoerd na de transactieactiegroep
  • rollback - start het proces om het systeem terug te brengen van de mislukte status naar de oorspronkelijke status

Het werkt zo.

Eerst moet u een transactie openen - roep de methode begin() of start() aan . Het aanroepen van deze methode geeft de status van het systeem aan waarnaar we zullen proberen terug te keren als er iets misgaat.

Vervolgens worden alle acties uitgevoerd, die worden gecombineerd tot een logische groep - een transactie.

Vervolgens wordt de methode commit() aangeroepen . Zijn oproep markeert het einde van een logische groep acties en begint meestal ook met het proces om deze acties in praktijk te brengen.

Bedenk hoe we iets in FileWriter schreven: eerst wordt alles wat we schreven in het geheugen opgeslagen, en als vervolgens de methode flush() wordt aangeroepen , worden alle gegevens uit de buffer in het geheugen naar schijf geschreven. Deze flush() is de transactie commit.

Welnu, als er een fout is opgetreden tijdens de transactie, moet u het proces starten om terug te keren naar de startstatus. Dit proces wordt rollback() genoemd en de methode met dezelfde naam is er meestal verantwoordelijk voor.

Grofweg zijn er 2 manieren om een ​​transactie te voltooien:

  • COMMIT - we bevestigen alle aangebrachte wijzigingen
  • ROLLBACK - draai alle aangebrachte wijzigingen terug

Transacties in JDBC

Vrijwel elk DBMS kan met transacties werken. JDBC heeft dus ook ondersteuning voor deze zaak. Alles is heel eenvoudig geïmplementeerd.

Eerst wordt elke aanroep van de methode execute() van het object Statement uitgevoerd in een afzonderlijke transactie. Hiervoor heeft Connection een AutoCommit- parameter . Als deze is ingesteld op true , wordt commit() aangeroepen na elke aanroep van de methode execute() .

Ten tweede, als u meerdere opdrachten in één transactie wilt uitvoeren, kunt u dit als volgt doen:

  • AutoCommit uitschakelen
  • onze bevelen roepen
  • roep de methode commit() expliciet aan

Het ziet er heel simpel uit:

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();

Als er een fout optreedt op de server terwijl de methode commit() wordt uitgevoerd , annuleert de SQL-server alle drie de acties.

Maar er zijn situaties waarin de fout zich nog steeds voordoet aan de kant van de client, en we zijn nooit bij de commit() methodeaanroep gekomen :

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();

Als er een fout optreedt tijdens de uitvoering van één executeUpdate() , wordt de methode commit() niet aangeroepen. Om alle uitgevoerde acties ongedaan te maken, moet u de methode rollback() aanroepen . Het ziet er meestal zo uit:

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();
}

Spaarpunten

Met de komst van JDBC 3.0 werd het mogelijk om efficiënter te werken met transactie rollback. Nu kunt u opslagpunten instellen - spaarpunten, en wanneer u de rollback () -bewerking aanroept , rolt u terug naar een specifiek opslagpunt.

Om op te slaan moet je een savepoint aanmaken, dit doe je met het commando:

Savepoint save = connection.setSavepoint();

Terugkeren naar een savepoint doe je met het commando:

connection.rollback(save);

Laten we proberen een savepoint toe te voegen vóór onze problematische opdracht:

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();
}

We hebben geneste transacties georganiseerd door een opslagpunt toe te voegen voordat de problematische methode wordt aangeroepen, en terug te keren naar de opgeslagen status door de rollback(save) -methode aan te roepen .

Ja, het lijkt erg op opslaan/laden in games.