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

时间:2010-07-01 18:47:37

标签: java jdbc

假设您有以下代码:

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)它不应该花费任何东西,对吧?

但显然,这些都不是特别引人注目。任何标准做法?

注意:我知道需要在关闭和回滚时重复try / catch。我实际上有一个中间件来抽象数据库访问并处理它,但我想知道是否添加它是多余的。

2 个答案:

答案 0 :(得分:46)

正常的习语如下:

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;
        }
    }
}

请注意,当close()块完成时,Java 7的try-with-resources statement始终隐式调用资源上的try,就好像它发生在finally中一样。

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

另见Connection#close()的javadoc(强调不是我的):

  

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

答案 1 :(得分:2)

Closing应该回滚,因为它在资源释放时不会提交,但是你的错误处理是特定的,所以如果要回滚异常,那就这样做。然后你可以在finally {}块中进行清理。 rollback()仅在出错时发生,在这种情况下,commit()不成功或甚至无法到达。

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

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