为什么我没有执行回滚时收到 "Cannot invoke a rollback operation when the AutoCommit mode is set to "true"."?

Why do I receive "Cannot invoke a rollback operation when the AutoCommit mode is set to "true".", when I did not execute a rollback?

执行以下结果异常"Cannot invoke a rollback operation when the AutoCommit mode is set to "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,这是真的,但这并没有什么不同。

如果那里有这个问题的答案,我就找不到了。我只找到有人说 "of course you cant rollback",结果是禁用自动提交。我不是要求回滚,那么它是从哪里来的呢? 根据 https://www.programcreek.com/java-api-examples/index.php?api=com.ibatis.common.jdbc.ScriptRunner 示例 3,我所做的应该有效。

我想在自动提交模式(默认的 MS SQL 服务器模式)下执行脚本,而不涉及或强制执行任何事务,除了 [=34] 中围绕每个单独语句的自动提交事务=] 脚本。我不想 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.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.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.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)

如果您将自动提交设置为关闭,那么您将负责保存您在数据库上的工作,因此在每次成功完成任务后,您都必须执行提交命令, 要关闭自动提交,请使用 connection.setAutoCommit(false) 当你的工作完成后执行 connection.commit() 将更改保存到数据库 或者在出现任何错误的情况下执行回滚命令 connection.rollback() 希望它帮助!!

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

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

现在很好,我们只在自动提交未打开时才提交。但是,如果抛出异常,则执行 finally 子句并且不考虑自动提交:

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

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

如果设置了记录器,异常会打印日志,我建议做如下操作:

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

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