外部事务失败时回滚内部事务

mib*_*lma 5 sql orm transactions h2 ormlite

我正在使用ORMLite访问Java中的h2数据库.要执行事务,我使用的是静态方法TransactionManager.callInTransaction.

在单个独立交易的情况下,这工作正常.但是,如果事务彼此嵌套,则即使外部事务失败,内部事务也会被提交.

就像在这段伪代码中一样:

OuterDatabaseTransaction
{
  Loop
  {
    InnerDatabaseTransaction
    {
      //Multiple update or create statements
      //One of the InnerDatabaseTransactions throws a random exception
    }
    //Alternatively the OuterDatabaseTransaction throws a random
    //exception but all commited InnerDatabaseTransactions should rollback still
  }
}
Run Code Online (Sandbox Code Playgroud)

所以我期望的是,如果任何内部事务失败,外部事务也会失败.如果外部事务失败,则没有任何内部事务被提交.目前似乎每个内部事务都是单独提交的,并且例如不与外部事务共享相同的Savepoint.

更新(谢谢)

查看跟踪显示以下内容

[TRACE] JdbcDatabaseConnection connection is closed returned false
[TRACE] JdbcDatabaseConnection connection autoCommit is true
[TRACE] JdbcDatabaseConnection connection set autoCommit to false
[DEBUG] TransactionManager had to set auto-commit to false
[TRACE] JdbcDatabaseConnection save-point sp14: id=0 name=ORMLITE15 set with name ORMLITE15
[DEBUG] TransactionManager started savePoint transaction ORMLITE15
[TRACE] JdbcDatabaseConnection connection is closed returned false
[TRACE] JdbcDatabaseConnection connection autoCommit is false
[TRACE] JdbcDatabaseConnection save-point sp15: id=0 name=ORMLITE16 set with name ORMLITE16
[DEBUG] TransactionManager started savePoint transaction ORMLITE16
[TRACE] JdbcDatabaseConnection connection is closed returned false
[TRACE] JdbcDatabaseConnection update statement is prepared and executed returning 1: <...>
[DEBUG] BaseMappedStatement update data with statement <...> changed 1 rows
[TRACE] BaseMappedStatement update arguments: <...>
[TRACE] JdbcDatabaseConnection connection is committed for save-point ORMLITE16
[DEBUG] TransactionManager committed savePoint transaction ORMLITE16
-> [ERROR] TransactionManager after commit exception, rolling back to save-point also threw exception
[TRACE] JdbcDatabaseConnection connection set autoCommit to true
[DEBUG] TransactionManager restored auto-commit to true
[TRACE] JdbcDatabaseConnection connection is closed returned false
Run Code Online (Sandbox Code Playgroud)

进入源代码会发现,在回滚OuterDatabaseTransaction期间,异常会在下面函数中的org.h2.engine.Session.java中的h2源中抛出.背后的原因然而我还不明白.

private void checkCommitRollback() {
  if (commitOrRollbackDisabled && locks.size() > 0) {
    throw DbException.get(ErrorCode.COMMIT_ROLLBACK_NOT_ALLOWED);
  }
}
Run Code Online (Sandbox Code Playgroud)

更新2

发布ORMLite Bug报告

den*_*ned 4

要查找原因,您可以打开跟踪级别日志记录。工作嵌套事务应生成如下日志:

TRACE: connection supports save points is true
TRACE: save-point <...> set with name ORMLITE1
DEBUG: started savePoint transaction ORMLITE1
...
TRACE: save-point <...> set with name ORMLITE2
DEBUG: started savePoint transaction ORMLITE2
...
TRACE: connection is committed for save-point ORMLITE2
...
TRACE: save-point <...> set with name ORMLITE3
DEBUG: started savePoint transaction ORMLITE3
...
TRACE: save-point ORMLITE3 is rolled back
...
TRACE: save-point ORMLITE1 is rolled back
Run Code Online (Sandbox Code Playgroud)

在此示例中,ORMLITE1 是外部事务的保存点,ORMLITE2 和 ORMLITE3 用于内部事务。第一个内部事务最初被提交,第二个事务回滚到 ORMLITE3 并导致外部事务回滚到 ORMLITE1,它又隐式取消了第一个内部事务。

但如果你在日志中看到这样的内容:

TRACE: connection supports save points is false
Run Code Online (Sandbox Code Playgroud)

那么 JDBC 驱动程序不支持保存点,并且嵌套事务将无法工作。理论上这不应该发生,因为 H2 声明支持保存点。

如果你看到这个:

ERROR: after commit exception, rolling back to save-point also threw exception
Run Code Online (Sandbox Code Playgroud)

然后回滚到保存点由于某种原因失败。检查你是否使用相同的ConnectionSource在外部和内部交易中使用相同的内容。

或者您在日志中发现了导致问题的其他内容。此外,将日志附加到您的问题可能会有所帮助。我建议用真正的Java代码替换伪代码。

更新

以下是您收到的错误的官方描述:

提交_回滚_不允许= 90058

如果对象被锁定,则尝试在触发器内调用提交或回滚,或者尝试调用触发器内隐式提交当前事务的方法时,会引发代码 90058 的错误。这并不是因为它会过早释放锁。

链接:http ://www.h2database.com/javadoc/org/h2/constant/ErrorCode.html#c90058

也许这将帮助您进一步找到问题的原因。对我来说,很难说更多没有看到你的代码。祝你好运!