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.
GO TO FULL VERSION