【问题标题】:Why do I receive "Cannot invoke a rollback operation when the AutoCommit mode is set to "true".", when I did not execute a rollback?当我没有执行回滚时,为什么会收到“当 AutoCommit 模式设置为“true”时无法调用回滚操作。”?
【发布时间】:2018-08-21 18:12:07
【问题描述】:

执行以下会导致异常“当 AutoCommit 模式设置为“true”时无法调用回滚操作。

java.sql.Connection connection = DriverManager.getConnection(connectionString);
com.ibatis.common.jdbc.ScriptRunner scriptRunner = new ScriptRunner(connection, true, true);
java.io.StringReader reader = new StringReader("PRINT 1;");
scriptRunner.runScript(reader);
// Cannot invoke a rollback operation when the AutoCommit mode is set to "true".

我的代码中没有引用回滚,我找不到任何选项来禁用它,以免被强制执行。我查看了standalone.xml 并尝试设置jta=false。我在 sqlMapConfig\transactionManager 上找到并设置了 commitRequired=false,它是 true,但这并没有什么不同。

如果这个问题的答案存在,我无法找到它。我发现的只是有人说“你当然不能回滚”,结果是禁用自动提交。我不是要求回滚,那么它来自哪里? 根据https://www.programcreek.com/java-api-examples/index.php?api=com.ibatis.common.jdbc.ScriptRunner 示例 3,我正在做的事情应该有效。

我想以自动提交模式(默认的 MS SQL Server 模式)执行脚本,而不涉及或强制执行任何事务,除了围绕 sql 脚本中每个单独语句的自动提交事务。我不希望 IMPLICIT_TRANSACTIONS ON,没有 BEGIN TRANSACTION,没有 COMMIT,绝对没有 ROLLBACK。

感谢您的宝贵时间

堆栈跟踪:

com.microsoft.sqlserver.jdbc.SQLServerException: Cannot invoke a rollback operation when the AutoCommit mode is set to "true".
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:191)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.rollback(SQLServerConnection.java:2037)
    at com.ibatis.common.jdbc.ScriptRunner.runScript(ScriptRunner.java:222)
    at com.ibatis.common.jdbc.ScriptRunner.runScript(ScriptRunner.java:114)
    at com.metric.DebugTests.DebugAutoCommit(DebugTests.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

【问题讨论】:

  • 显示完整的堆栈跟踪。可能有一个错误,ibatis 尝试回滚,这是明智的做法。
  • 我添加了堆栈跟踪。
  • 是的,看看ScriptRunner.java:222 是如何调用回滚的。但是,如果存在潜在的异常,这可能会影响它,并且您不知道真正的问题是什么。你可以看看是否可以将ScriptRunner 配置为不尝试回滚。
  • 根据github.com/mybatis/ibatis-2/blob/master/src/main/java/com/…,conn.rollback();是在最后,没有检查禁用它。看起来它的版本不同,但内容丰富。

标签: java sql-server jdbc ibatis


【解决方案1】:

基于对ScriptRunner 的快速浏览(不是问题中的确切版本,但足够接近),我们可以看到以下代码

if (!autoCommit) {
    conn.commit();
}

现在很好,我们只在未启用自动提交的情况下提交。但是,如果抛出异常,则执行 finally 子句并且不考虑自动提交:

} finally {
  conn.rollback();
  flush();
}

这将导致原始异常详细信息丢失。

由于如果设置了记录器,异常会打印日志,我建议执行以下操作:

scriptRunner.setErrorLogWriter(somePrintWriter); // Some PrintWriter, maybe to a file

这样您就可以找出原始异常。这也绝对是一个错误,因此需要报告(似乎我没有 github 凭据,因此拥有这些凭据的人可能会提出问题(或者嘿,为什么不提交拉取请求))。

【讨论】:

  • 即使没有异常,finally 也会运行。我会按照你的建议添加记录器,看看是否有。无论哪种方式,finally 中的回滚都需要围绕它有更多的逻辑。不幸的是,这对我的任务没有帮助,但至少我现在知道为什么了。谢谢
  • @Russ 啊当然,所以可能没有潜在的异常(这当然很好)。顺便说一句,您使用的是哪个版本,看来 ibatis2 已经过时了。您可能想尝试最新版本。此错误已在 mybatis-3 中修复。
  • 我们使用的是ibatis-2.3.4.726.jar。我相信我们正在努力迁移到 mybatis。我将不得不检查它是否有同样的问题,希望没有。如果没有,那么早晚搬家可能就是答案。我能够验证没有发生错误。
【解决方案2】:

如果你设置了自动提交,那么你有责任保存你在数据库上的工作,所以在每一个成功的任务之后你必须执行一个提交命令, 要设置自动提交关闭使用connection.setAutoCommit(false) 当你的工作完成后执行 connection.commit() 保存对数据库的更改 或者在任何错误的情况下执行回滚命令connection.rollback() 希望它有帮助!

【讨论】:

    猜你喜欢
    • 2016-03-07
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多