Hvorfor transaktioner er nødvendige
Meget ofte, når man arbejder med en database, opstår der en situation, hvor man skal udføre mange forskellige handlinger, men de giver kun mening sammen.
For eksempel skriver vi banksoftware, der skal gøre tre ting:
- Hæv penge fra kundens konto
- Tilføj penge til modtagerens konto
- Registrer bogføringsdataene i "postlog"
Hvis der opstår en fejl under udførelsen af en af disse handlinger, skal de to andre også annulleres. Det er umuligt at afskrive penge fra klienten og ikke tilføje dem til modtageren? Nå, eller tilføje til modtageren, men ikke afskrive fra klienten?
Så en sådan logisk gruppering af forskellige handlinger i én kaldes en transaktion . Med andre ord er en transaktion en gruppe af handlinger, der kun skal udføres samlet . Hvis en handling mislykkedes eller blev udført med en fejl, skal alle andre handlinger annulleres.
En transaktion har normalt tre tilstande:
- initial tilstand - systemets tilstand før udførelse af en gruppe handlinger
- succestilstand - tilstand efter aktionsgruppen er afsluttet
- mislykket tilstand - noget gik galt
I dette tilfælde er der normalt tre kommandoer:
- start/start - udføres før starten af den logiske gruppe af handlinger
- commit - udføres efter transaktionshandlingsgruppen
- rollback - starter processen med at returnere systemet fra mislykket tilstand til initial tilstand
Det fungerer sådan her.
Først skal du åbne en transaktion - kald start()- eller start()- metoden . At kalde denne metode angiver systemets tilstand, som vi vil forsøge at vende tilbage til, hvis noget går galt.
Derefter udføres alle handlinger, som kombineres til en logisk gruppe - en transaktion.
Derefter kaldes commit() -metoden . Dens opfordring markerer afslutningen på en logisk gruppe af handlinger og starter normalt også processen med at omsætte disse handlinger i praksis.
Husk, hvordan vi skrev noget i FileWriter: Først gemmes alt, hvad vi skrev i hukommelsen, og når flush () -metoden kaldes , bliver alle data fra bufferen i hukommelsen skrevet til disken. Denne flush() er transaktionsbekræftelsen.
Nå, hvis der opstod en fejl under driften af transaktionen, skal du starte processen med at vende tilbage til starttilstanden. Denne proces kaldes rollback() , og metoden af samme navn er normalt ansvarlig for den.
Groft sagt er der 2 måder at gennemføre en transaktion på:
- COMMIT - vi bekræfter alle de ændringer, der er foretaget
- TILBAGE - rulle alle ændringer tilbage
Transaktioner i JDBC
Næsten alle DBMS kan arbejde med transaktioner. Så JDBC har også støtte til denne sag. Alt er implementeret meget enkelt.
Først udføres hvert kald til execute()- metoden for Statement-objektet i en separat transaktion. For at gøre dette har Connection en AutoCommit- parameter . Hvis den er sat til true , vil commit() blive kaldt efter hvert kald til execute() metoden .
For det andet, hvis du vil udføre flere kommandoer i en transaktion, så kan du gøre det sådan her:
- deaktiver AutoCommit
- kalder vores kommandoer
- kald commit() metoden eksplicit
Det ser meget simpelt ud:
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();
Hvis der opstår en fejl på serveren, mens commit() -metoden kører , annullerer SQL-serveren alle tre handlinger.
Men der er situationer, hvor fejlen stadig opstår på klientsiden, og vi aldrig nåede til commit()- metodekaldet :
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();
Hvis der opstår en fejl under udførelsen af en executeUpdate() , vil commit()- metoden ikke blive kaldt. For at rulle alle handlinger tilbage, skal du kalde rollback()- metoden . Det ser normalt sådan ud:
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();
}
Sparepunkter
Med fremkomsten af JDBC 3.0 blev det muligt at arbejde mere effektivt med tilbagerulning af transaktioner. Nu kan du indstille gem point - gem point, og når du kalder rollback () operationen , skal du rulle tilbage til et specifikt gemt punkt.
For at gemme skal du oprette et savepoint, dette gøres med kommandoen:
Savepoint save = connection.setSavepoint();
Retur til et lagringspunkt udføres med kommandoen:
connection.rollback(save);
Lad os prøve at tilføje et savepoint før vores problematiske 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 organiserede indlejrede transaktioner ved at tilføje et save-point , før vi kalder den problematiske metode, og vende tilbage til den gemte tilstand ved at kalde rollback(save) -metoden .
Ja, det minder meget om at gemme/indlæse i spil.
GO TO FULL VERSION