假设您有以下代码:
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。我实际上有一个中间件来抽象数据库访问并处理它,但我想知道是否添加它是多余的。
答案 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();
}
}