Использование точек сохранения
Точки сохранения предоставляют механизм отката части транзакций. В SQL Server точку сохранения можно создать с помощью инструкции SAVE TRANSACTION savepoint_name. После выполняется инструкция ROLLBACK TRANSACTION savepoint_name для отката до точки сохранения вместо отката до начала транзакции.
Точки сохранения удобно использовать, когда вероятность возникновения ошибок мала. Откат до точки сохранения в ситуации, когда ошибка встречается крайне редко, часто более эффективен, чем подход, когда каждая транзакция проверяет допустимость обновления, прежде чем его выполнить. Операции обновления и отката являются ресурсоемкими, поэтому точки сохранения приносят пользу, только если вероятность ошибок небольшая, а затраты на проверку допустимости обновления относительно высокие.
Драйвер Microsoft JDBC для SQL Server поддерживает использование точек сохранения посредством метода setSavepoint класса SQLServerConnection. С помощью метода setSavepoint можно создать именованную или неименованную точку сохранения в текущей транзакции, а метод возвращает объект SQLServerSavepoint. В транзакции можно создать несколько точек сохранения. Для отката транзакции до заданной точки сохранения можно передать объект SQLServerSavepoint в метод rollback (java.sql.Savepoint).
В приведенном ниже примере используется точка сохранения при выполнении локальной транзакции, состоящей из двух раздельных инструкций в блоке try
. Инструкции выполняются в таблице Production.ScrapReason в примере базы данных AdventureWorks2022, а для отката второй инструкции используется точка сохранения. При этом в базе данных фиксируется только первая инструкция.
public static void executeTransaction(Connection con) {
try(Statement stmt = con.createStatement();) {
con.setAutoCommit(false);
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Correct width')");
Savepoint save = con.setSavepoint();
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong width')");
con.rollback(save);
con.commit();
System.out.println("Transaction succeeded.");
}
catch (SQLException ex) {
ex.printStackTrace();
try {
System.out.println("Transaction failed.");
con.rollback();
}
catch (SQLException se) {
se.printStackTrace();
}
}
}