Miért van szükség tranzakciókra

Nagyon gyakran az adatbázissal való munka során olyan helyzet adódik, amikor sok különböző műveletet kell végrehajtania, de ezeknek csak együtt van értelme.

Például banki szoftvert írunk, amelynek három dolgot kell tennie:

  • Pénz felvétele az ügyfél számlájáról
  • Adjon hozzá pénzt a címzett számlájához
  • A feladási adatokat rögzítse a „feladási naplóban”

Ha ezen műveletek bármelyikének végrehajtása során hiba történik, akkor a másik kettőt is törölni kell. Lehetetlen pénzt leírni az ügyfélről, és nem hozzáadni a címzetthez? Nos, vagy hozzáadja a címzetthez, de nem írja le az ügyfélről?

Tehát a különböző műveletek ilyen logikai csoportosítását tranzakciónak nevezzük . Más szavakkal, a tranzakció olyan műveletek csoportja, amelyeket csak együtt kell végrehajtani . Ha valamelyik művelet meghiúsult vagy hibásan hajtódott végre, akkor az összes többi műveletet törölni kell.

Egy tranzakciónak általában három állapota van:

  • kezdeti állapot - a rendszer állapota egy műveletcsoport végrehajtása előtt
  • sikerállapot – az akciócsoport befejezése utáni állapot
  • sikertelen állapot – valami elromlott

Ebben az esetben általában három parancs van:

  • start/start - a műveletek logikai csoportjának kezdete előtt végrehajtva
  • commit – a tranzakciós műveletcsoport után végrehajtva
  • visszaállítás – elindítja a rendszer visszaállításának folyamatát a sikertelen állapotból a kezdeti állapotba

Ez így működik.

Először meg kell nyitnia egy tranzakciót - hívja meg a begin() vagy start() metódust . Ennek a metódusnak a meghívása jelzi a rendszer állapotát, amelyhez megpróbálunk visszatérni, ha valami baj van.

Ezután minden művelet végrehajtásra kerül, amelyeket egy logikai csoportba - tranzakcióba - egyesítenek.

Ekkor a commit() metódust hívjuk meg . Felhívása a cselekvések logikai csoportjának végét jelzi, és általában elindítja e cselekvések gyakorlatba ültetésének folyamatát.

Emlékezzünk vissza, hogyan írtunk valamit a FileWriterben: először minden, amit írtunk, a memóriában tárolódik, majd a flush () metódus meghívásakor a memóriában lévő puffer összes adata lemezre kerül. Ez a flush() a tranzakció véglegesítése.

Nos, ha hiba történt a tranzakció során, akkor meg kell indítani a kiindulási állapotba való visszatérés folyamatát. Ezt a folyamatot rollback() -nek hívják , és általában az azonos nevű metódus a felelős érte.

Nagyjából kétféleképpen lehet tranzakciót végrehajtani:

  • COMMIT – minden változtatást megerősítünk
  • ROLLBACK – minden változtatás visszaállítása

Tranzakciók a JDBC-ben

Szinte minden DBMS képes együttműködni a tranzakciókkal. Tehát a JDBC is támogatja ezt az esetet. Mindent nagyon egyszerűen hajtanak végre.

Először is, a Statement objektum execute() metódusának minden egyes hívása külön tranzakcióban kerül végrehajtásra. Ehhez a Connection rendelkezik egy AutoCommit paraméterrel . Ha igaz értékre van állítva , akkor a commit() az execute() metódus minden egyes hívása után meghívásra kerül .

Másodszor, ha több parancsot szeretne végrehajtani egy tranzakcióban, akkor ezt a következőképpen teheti meg:

  • letiltja az automatikus kommit
  • hívjuk csapatainkat
  • kifejezetten hívja a commit() metódust

Nagyon egyszerűnek tűnik:

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

Ha hiba történik a kiszolgálón, miközben a commit() metódus fut , akkor az SQL-kiszolgáló mindhárom műveletet megszakítja.

De vannak olyan helyzetek, amikor a hiba továbbra is megjelenik a kliens oldalon, és soha nem jutottunk el a commit() metódushívásig :

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

Ha hiba történik egy executeUpdate() végrehajtása során , akkor a commit() metódus nem kerül meghívásra. Az összes végrehajtott művelet visszaállításához meg kell hívnia a rollback() metódust . Általában így néz ki:

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

Mentési pontok

A JDBC 3.0 megjelenésével lehetővé vált a tranzakciók visszaállításával való hatékonyabb munkavégzés. Most beállíthat mentési pontokat – pontokat menthet el, és amikor meghívja a visszaállítási () műveletet , lépjen vissza egy adott mentési pontra.

A mentéshez létre kell hoznia egy mentési pontot, ez a következő paranccsal történik:

Savepoint save = connection.setSavepoint();

A mentési ponthoz való visszatérés a következő paranccsal történik:

connection.rollback(save);

Próbáljunk meg egy mentési pontot hozzáadni a problémás parancsunk elé:

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

A beágyazott tranzakciókat úgy szerveztük meg, hogy a problémás metódus meghívása előtt mentési pontot adtunk hozzá, majd a rollback(save) metódus meghívásával tértünk vissza a mentett állapotba .

Igen, nagyon hasonlít a játékokban való mentéshez/betöltéshez.