Varför transaktioner behövs

Mycket ofta, nÀr man arbetar med en databas, uppstÄr en situation nÀr man behöver utföra mÄnga olika ÄtgÀrder, men de Àr bara meningsfulla tillsammans.

Till exempel skriver vi bankprogram som ska göra tre saker:

  • Ta ut pengar frĂ„n kundens konto
  • LĂ€gg till pengar pĂ„ mottagarens konto
  • Registrera inlĂ€ggsdata i "inlĂ€ggsloggen"

Om ett fel uppstÄr under utförandet av nÄgon av dessa ÄtgÀrder, mÄste de andra tvÄ ocksÄ avbrytas. Det Àr omöjligt att skriva av pengar frÄn kunden och inte lÀgga till dem till mottagaren? Tja, eller lÀgga till mottagaren, men inte skriva av frÄn klienten?

SÄ en sÄdan logisk gruppering av olika ÄtgÀrder till en kallas en transaktion . Med andra ord Àr en transaktion en grupp av ÄtgÀrder som endast mÄste utföras tillsammans . Om nÄgon ÄtgÀrd misslyckades eller utfördes med ett fel mÄste alla andra ÄtgÀrder avbrytas.

En transaktion har vanligtvis tre tillstÄnd:

  • initialtillstĂ„nd - systemets tillstĂ„nd innan en grupp av Ă„tgĂ€rder utförs
  • framgĂ„ngstillstĂ„nd - tillstĂ„nd efter att Ă„tgĂ€rdsgruppen Ă€r klar
  • misslyckat tillstĂ„nd - nĂ„got gick fel

I det hÀr fallet finns det vanligtvis tre kommandon:

  • start/start - exekveras före starten av den logiska gruppen av Ă„tgĂ€rder
  • commit - utförs efter transaktionsĂ„tgĂ€rdsgruppen
  • rollback - startar processen att Ă„terstĂ€lla systemet frĂ„n misslyckat tillstĂ„nd till initialt tillstĂ„nd

Det fungerar sÄ hÀr.

Först mÄste du öppna en transaktion - anropa start() eller start()- metoden . Att anropa denna metod indikerar tillstÄndet för systemet som vi kommer att försöka ÄtervÀnda till om nÄgot gÄr fel.

Sedan utförs alla ÄtgÀrder, som kombineras till en logisk grupp - en transaktion.

Sedan kallas metoden commit() . Dess uppmaning markerar slutet pÄ en logisk grupp av ÄtgÀrder och startar ocksÄ vanligtvis processen att omsÀtta dessa ÄtgÀrder i praktiken.

Kom ihÄg hur vi skrev nÄgot i FileWriter: först lagras allt vi skrev i minnet, och sedan nÀr flush () -metoden anropas skrivs all data frÄn bufferten i minnet till disken. Denna flush() Àr transaktionsbekrÀftelsen.

Tja, om ett fel intrÀffade under transaktionens drift, mÄste du initiera processen för att ÄtergÄ till starttillstÄndet. Denna process kallas rollback() , och metoden med samma namn Àr vanligtvis ansvarig för den.

Grovt sett finns det tvÄ sÀtt att slutföra en transaktion:

  • ÅTGÄRDER - vi bekrĂ€ftar alla Ă€ndringar som gjorts
  • ROLLBACK - rulla tillbaka alla gjorda Ă€ndringar

Transaktioner i JDBC

NÀstan alla DBMS kan arbeta med transaktioner. SÄ JDBC har ocksÄ stöd för det hÀr fallet. Allt genomförs vÀldigt enkelt.

Först exekveras varje anrop till execute() -metoden för Statement-objektet i en separat transaktion. För att göra detta har Connection en AutoCommit- parameter . Om den Àr satt till true kommer commit() att anropas efter varje anrop till execute()- metoden .

För det andra, om du vill utföra flera kommandon i en transaktion, kan du göra det sÄ hÀr:

  • inaktivera AutoCommit
  • kallar vĂ„ra kommandon
  • anropa commit() -metoden explicit

Det ser vÀldigt enkelt ut:

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

Om ett fel uppstÄr pÄ servern medan commit() -metoden körs kommer SQL-servern att avbryta alla tre ÄtgÀrderna.

Men det finns situationer nÀr felet fortfarande uppstÄr pÄ klientsidan, och vi kom aldrig till commit()- metodanropet :

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

Om ett fel intrÀffar under körningen av en executeUpdate() , kommer metoden commit() inte att anropas. För att ÄterstÀlla alla vidtagna ÄtgÀrder mÄste du anropa metoden rollback() . Det brukar se ut sÄ hÀr:

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

RĂ€ddningspunkter

Med tillkomsten av JDBC 3.0 blev det möjligt att arbeta mer effektivt med ÄterstÀllning av transaktioner. Nu kan du stÀlla in spara poÀng - spara poÀng, och nÀr du anropar ÄterstÀllningsoperationen () rullar du tillbaka till en specifik sparpunkt.

För att spara behöver du skapa en rÀddningspunkt, detta görs med kommandot:

Savepoint save = connection.setSavepoint();

ÅtergĂ„ till en rĂ€ddningspunkt görs med kommandot:

connection.rollback(save);

LÄt oss försöka lÀgga till en rÀddningspunkt före vÄrt problematiska kommando:

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

Vi organiserade kapslade transaktioner genom att lÀgga till en spara-punkt innan vi anropade den problematiska metoden och ÄtervÀnde till det sparade tillstÄndet genom att anropa rollback(save) -metoden .

Ja, det Àr vÀldigt likt att spara/ladda i spel.