con.rollback() 是否会回滚 con.commit() 已经提交的更改?

Will con.rollback() rollback already commited changes by con.commit()?

我现在正在做 Legacy 项目,它需要一些深入的底层知识 JDBC API 在某些地方,我看到这样的代码:

try {
    con = ....
    con.setAutoCommit(false);
    //insert_1 pack to db
    con.commit();
    //insert_2 pack to db
    con.commit();
    //insert_3 pack to db
    con.commit();
} catch (SQLException e) {
    try {
        con.rollback();
    } catch (SQLException e) {
        log.warn("SQLException on rolling back the destination connection. ", e);
            throw e;
        }
    throw ex;
}

有时 con.rollback();未在 catch 中调用:

try {
        con = ....
        con.setAutoCommit(false);
        //insert_1 pack to db
        con.commit();
        //insert_2 pack to db
        con.commit();
        //insert_3 pack to db
        con.commit();
    } catch (SQLException e) {      
        throw new MyBusinessException(ex);
    }

能否请您从交易的角度解释一下差异?

P.S. 我已阅读 java 回滚文档,但它没有回答我的问题。

Undoes all changes made in the current transaction and releases any database locks currently held by this Connection object. This method should be used only when auto-commit mode has been disabled. Throws: SQLException – if a database access error occurs, this method is called while participating in a distributed transaction, this method is called on a closed connection or this Connection object is in auto-commit mode See Also: setAutoCommit

代码看起来不正确。

  1. 执行了多个提交。这意味着显式回滚可以将状态回滚到最后一次提交的开始。我想这不是回滚应该做的。

  2. 如果没有调用显式回滚,至少在池化数据库连接中(在池化数据库连接中,连接永远不会关闭,但会重复使用)已经执行的语句仍在事务中。 IE。稍后在这里调用 rollback 会导致奇怪的错误,并且还会回滚实际上与当前业务流程无关的最后执行的语句。我在 Hikari Connection Pool Implementation that dirty states are automatically rolled back, but maybe this correct behavior cannot be assumed for every implementation. E.g. the Apache DBCP 中看到代码并不是那么直截了当,询问维护者是否这样做应该会有帮助。

  3. 我没有看到 close 来电。

对于您的问题,这意味着第二个代码片段应该:

  1. 在单个非池连接中,在最后一次提交后不提交最后的语句,这是正确的(偶然)。
  2. 在池连接中,让事务挂起,这可能会导致错误,即下一个业务逻辑提交某些内容并重新使用连接也会提交此错误。