Защо са необходими транзакции
Много често, когато работите с база данни, възниква ситуация, когато трябва да извършите много различни действия, но те имат смисъл само заедно.
Например, ние пишем банков софтуер, който трябва да прави три неща:
- Tagлене на пари от сметката на клиента
- Добавете пари към сметката на получателя
- Запишете данните за публикуване в „дневник на публикуване“
Ако възникне грешка по време на изпълнението на някое от тези действия, тогава другите две също трябва да бъдат отменени. Невъзможно е да отпишете пари от клиента и да не ги добавите към получателя? Е, or да добавите към получателя, но не и да отпишете от клиента?
И така, такова логическо групиране на различни действия в едно се нарича транзакция . С други думи, транзакцията е група от действия, които трябва да се извършват само всички заедно . Ако някое действие е неуспешно or е изпълнено с грешка, тогава всички други действия трябва да бъдат отменени.
Една транзакция обикновено има три състояния:
- начално състояние - състоянието на системата преди изпълнение на група от действия
- успех състояние - състояние след завършване на групата действия
- провалена държава - нещо се обърка

В този случай обикновено има три команди:
- start/start - изпълнява се преди началото на логическата група действия
- commit - изпълнява се след групата за действие на транзакция
- връщане назад - стартира процеса на връщане на системата от неуспешно състояние в първоначално състояние
Работи така.
Първо трябва да отворите транзакция - извикайте метода begin() or start() . Извикването на този метод показва състоянието на системата, към което ще се опитаме да се върнем, ако нещо се обърка.
След това се извършват всички действия, които се обединяват в логическа група - транзакция.
Тогава методът commit() се извиква . Неговото извикване маркира края на логическа група от действия и обикновено започва процеса на прилагане на тези действия на практика.
Спомнете си How написахме нещо във FileWriter: първо всичко, което написахме, се съхранява в паметта, а след това, когато се извика методът flush () , всички данни от буфера в паметта се записват на диска. Този flush() е ангажиментът на транзакцията.
Е, ако е възникнала грешка по време на операцията на транзакцията, тогава трябва да започнете процеса на връщане към началното състояние. Този процес се нарича rollback() и обикновено за него отговаря методът със същото име.
Грубо казано, има 2 начина за извършване на транзакция:
- COMMIT - потвърждаваме всички напequalsи промени
- ROLLBACK - връщане назад на всички напequalsи промени
Транзакции в JDBC
Почти всяка СУБД може да работи с транзакции. Така че JDBC също има поддръжка за този случай. Всичко се изпълнява много просто.
Първо, всяко извикване на метода execute() на обекта Statement се изпълнява в отделна транзакция. За да направите това, Connection има параметър AutoCommit . Ако е зададено на true , тогава commit() ще се извиква след всяко извикване на метода execute() .
Второ, ако искате да изпълните няколко команди в една транзакция, можете да го направите по следния начин:
- деактивирайте AutoCommit
- извикване на нашите команди
- извикайте изрично метода commit().
Изглежда много просто:
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();
Ако възникне грешка на сървъра, докато се изпълнява методът commit() , тогава SQL сървърът ще отмени и трите действия.
Но има ситуации, когато грешката все още възниква от страна на клиента и никога не сме стигнали до извикването на метода commit() :
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();
Ако възникне грешка по време на изпълнението на един executeUpdate() , тогава методът commit() няма да бъде извикан. За да отмените всички предприети действия, трябва да извикате метода rollback() . Обикновено изглежда така:
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();
}
Точки за запазване
С появата на JDBC 3.0 стана възможно да се работи по-ефективно с връщане назад на транзакции. Сега можете да зададете точки за запазване - запишете точки и когато извикате операцията за връщане назад () , върнете се до конкретна точка за запазване.
За да запазите, трябва да създадете точка за запис, това става с командата:
Savepoint save = connection.setSavepoint();
Връщането към точка за запис се извършва с командата:
connection.rollback(save);
Нека опитаме да добавим точка за запис преди нашата проблемна команда:
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();
}
Организирахме вложени транзакции, като добавихме точка за запазване, преди да извикаме проблемния метод, и се върнахме към запазеното състояние, като извикаме метода за връщане (запазване) .
Да, много е подобно на запазване/зареждане в игрите.
GO TO FULL VERSION