В JDBC, когда autocommit является ложным и никаких явных точек сохранения не установлено, это хороший стиль или отходы для отката?

Скажите, что у вас есть следующий код:

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) Это ничего не стоило, правда?

Но, очевидно, ни одно из них не является особенно убедительным. Любая стандартная практика?

Примечание. Я знаю о необходимости повторить попытку/улов при закрытии и откате. На самом деле у меня есть промежуточное программное обеспечение, которое абстрагирует доступ к базе данных и заботится об этом, но мне было интересно, добавляет ли это лишнее.

Ответ 1

Нормальная идиома такова:

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() также является обязательным, если речь идет о объединенном соединении. А именно, это будет reset транзакционное состояние соединения. close() объединенного соединения не сделает этого, только теги commit() и rollback() сделают это. Не вызывать rollback() может привести к тому, что следующая аренда объединенного соединения будет по-прежнему иметь (успешные) запросы предыдущей транзакции в ее памяти.

См. также javadoc Connection#close() (не мой):

Настоятельно рекомендуется , что приложение явно совершает или откатывает активную транзакцию до вызова метода close. Если вызывается метод close и есть активная транзакция, результаты определяются реализацией.

Ответ 2

Закрытие должно откат, потому что оно не будет выполняться при освобождении ресурсов, но полезно иметь конкретную обработку ошибок, поэтому, если вы хотите откат на исключение, сделайте это. Затем вы можете выполнить очистку в блоке finally {}. Откат() происходит только при ошибке, и в этом случае ваш commit() не будет успешным или даже не достигнут.

Connection conn = null;
try {
    conn = ...

    ...
    conn.commit();
}
catch (SQLException e) {
    if (conn != null) {
        conn.rollback();
    }
}
finally {
    if (conn != null) {
        conn.close();
    }
}