我们应该在什么情况下调用connection.rollback()方法?

6
请告诉我什么情况下需要调用connection.rollback()方法。
try{
  connection = getConnection();
  connection.setAutoCommit(false);
  pstmt1 = connection.preparedstatement ( ... );
  ...
  pstt1.executeUpdate();
  pstmt2 = connection.preparedstatement ( ... );
  ...
  pstt2.executeUpdate();
  connection.commit();
}catch ( Exception sqe ) {  sqe.printStacktrace();
}finally {
  closeQuitely ( pstmt1 );
  closeQuitely ( pstmt2 );
  closeQuitely ( connection );
}

在上述代码中,我们没有使用connection.rollback()方法,但即使发生异常,一切也将正常工作[我猜],因为连接已经设置为自动提交=false模式。
那么什么情况下我们需要使用这个方法呢?请附带示例。

简单回答:程序员不应手动调用rollback()或commit()。 - SteveD
除了学习JDBC、编写库/框架或进行性能关键的操作之外,我不建议使用原始的JDBC - 使用Spring、JPA或其他框架来自动处理事务和连接。这样做太容易出错,并且需要大量的样板代码。 - SteveD
3个回答

6
当您关闭连接时,您的事务将被终止。大多数DBMS都会回滚您的事务,因为它们不知道连接终止的情况(也许您的程序被杀死了?)。如果您已经提交了,回滚将不起作用。
另一方面,如果您正在使用连接池技术,当您关闭连接时,池管理器会拦截它,并且可能(希望)回滚连接并保持连接处于打开状态。
在catch子句中回滚是好的做法,甚至在finally子句中回滚也可以。在提交后执行不必要的回滚通常不会有影响。
顺便说一下,如果您正在使用Postgres,则最好在开始之前回滚以确保重置事务启动时间。这是因为Postgres将current_timestamp值保留到事务开始的时间,如果您使用池化连接,这可能是很久以前的时间!

1
在某些应用服务器中存在连接池时,关闭连接将不会回滚事务。这是一种故意的性能优化,它意味着第二个打开连接实际上将给出相同的连接,仍然与事务相关联。 - djna

5
在异常情况下,您的事务未解决。最终它会超时,并且像您所说的那样会回滚。但在此之前(可能需要几分钟),您的事务获取的所有锁都将被保留。连接无法意识到您可能不只是要提交()。像这样长时间持有锁对于并发性来说非常不利。
在异常情况下添加回滚。
关闭连接似乎也会终止事务。然而,在使用简单JDBC时,在应用程序服务器中实现连接池时,关闭连接具有“返回到池”的语义,并且连接池将保留连接与当前事务的关联。如果稍后在代码中仍处于同一事务范围内,请请求一个连接,池将返回相同的连接。这对于编写模块化应用程序非常方便,但代价是您不能假设关闭连接会解决事务。
begin tran

// call a method
    get connection

    work

    close connection

// call another method

    get connection  // you get the **same** connection still associated with the tran

    work

    close connection

commit

它会超时吗?我认为静止最终会放弃交易。 - Miserable Variable
是的,在连接池的情况下它会。我已经扩展了答案,以便更清楚地说明这一点。 - djna

0
如果您在没有提交的情况下关闭连接,则事务将被回滚。如果您正在使用连接池,则它可能已经为您执行了此操作。
当您遇到不会引发异常但仍不想提交的条件时,显式回滚可能更合适。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接