В JDBC, когда autocommit имеет значение false и не были заданы явные точки сохранения, это хороший стиль или пустая трата для отката?
Скажем, у вас есть следующий код:
Connection conn;
try
{
conn = ... // get connection
conn.setAutoCommit(false);
... // Do some modification queries and logic
conn.commit()
} catch(SQLException e)
{
conn.rollback() // Do we need this?
conn.close()
}
В этом коде, если есть исключение, лучше ли просто закрыть соединение (так как автокоммит выключен), или явно откатить и затем закрыть соединение? Там нет точек сохранения.
Я чувствую, что имеет смысл добавить вызов отката, потому что:
1) Кто-то в будущем может добавить точки сохранения, но забыть добавить откат
2) улучшает читаемость
3) Это ничего не должно стоить, верно?
Но очевидно, что ничего из этого не является особенно убедительным. Любая стандартная практика?
Примечание. Мне известно о необходимости повторной попытки / отлова при закрытии и откате. У меня фактически есть промежуточное программное обеспечение, которое абстрагирует доступ к базе данных и заботится об этом, но мне было интересно, было ли добавление этого излишним.
2 ответа
Нормальная идиома следующая:
public void executeSomeQuery() throws SQLException {
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement statement = connection.prepareStatement(SOME_SQL)) {
// Fire transactional queries here.
connection.commit();
} catch (SQLException e) {
connection.rollback();
throw e;
}
}
}
Обратите внимание, что в Java 7 оператор try-with-resources всегда неявно вызывает close()
на ресурсе, когда try
блок заканчивается, как будто это происходит в finally
,
призвание rollback()
также является обязательным, когда речь идет о пуле соединений. А именно, он сбросит транзакционное состояние соединения. close()
соединения в пуле не будет делать это, только commit()
а также rollback()
сделаю это. Не звонит rollback()
Это может привести к тому, что при следующей аренде пула соединений в памяти останутся (успешные) запросы предыдущей транзакции.
Смотрите также Connection#close()
(акцент не мой):
Настоятельно рекомендуется, чтобы приложение явно зафиксировало или откатило активную транзакцию до вызова
close
метод. Еслиclose
Метод вызывается, и есть активная транзакция, результаты определяются реализацией.
Закрытие должно откатиться, потому что оно не будет зафиксировано, когда ресурсы будут освобождены, но хорошо, чтобы обработка ошибок была конкретной, поэтому, если вы хотите откатить исключение, сделайте это. Затем вы можете выполнить очистку в блоке finally{}. Откат () происходит только при ошибке, в этом случае ваш commit() не был успешным или даже не был достигнут.
Connection conn = null;
try {
conn = ...
...
conn.commit();
}
catch (SQLException e) {
if (conn != null) {
conn.rollback();
}
}
finally {
if (conn != null) {
conn.close();
}
}