在 JDBC 中,当自动提交为 false 并且没有设置显式保存点时,回滚是好样式还是浪费?

2022-09-01 04:37:25

假设您有以下代码:

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

当涉及池连接时,呼叫也是必需的。也就是说,它将重置连接的事务状态。池连接不会这样做,只有 和 会这样做。不调用可能会导致池连接的下一个租约在其内存中仍然具有上一个事务的(成功)查询。rollback()close()commit()rollback()rollback()

另请参阅 Connection#close() 的 javadoc(强调不是我的):

强烈建议应用程序在调用该方法之前显式提交或回滚活动事务。如果调用该方法并且存在活动事务,则结果是实现定义的。closeclose


答案 2

关闭应该回滚,因为它在资源释放时不会提交,但最好是让错误处理具体化,所以如果你想在异常上回滚,请这样做。然后,您可以在 final{} 块中进行清理。回滚()仅在出错时发生,在这种情况下,您的提交()不成功或甚至没有达到。

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

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

推荐