{"record":{"id":"09492d933a094a26","repo":"tursodatabase/turso","slug":"cannot-rollback-in-autocommit-mode","errorCode":null,"errorMessage":"Cannot rollback in autocommit mode.","messagePattern":"Cannot rollback in autocommit mode\\.","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoConnection.java","lineNumber":239,"sourceCode":"      }\n\n      if (inTransaction) {\n        executeInternal(\"COMMIT\");\n        inTransaction = false;\n      }\n    }\n  }\n\n  /**\n   * Rolls back the current transaction.\n   *\n   * @throws SQLException if in auto-commit mode, closed, or database error occurs.\n   */\n  public void rollback() throws SQLException {\n    synchronized (transactionLock) {\n      checkOpen();\n      if (autoCommit) {\n        throw new SQLException(\"Cannot rollback in autocommit mode.\");\n      }\n\n      if (inTransaction) {\n        executeInternal(\"ROLLBACK\");\n        inTransaction = false;\n      }\n    }\n  }\n\n  /**\n   * Lazy transaction starter. Starts a transaction if one isn't active, auto-commit is disabled,\n   * and the statement isn't a control command.\n   */\n  private void ensureTransactionStarted(String sql) throws SQLException {\n    if (autoCommit || inTransaction) return;\n\n    // Avoid recursive start for control statements\n    String trimmed = sql.trim().toUpperCase();","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/core/TursoConnection.java#L221-L257","documentation":"TursoConnection.rollback() refuses to run while autoCommit is true. With autocommit enabled each statement is committed on completion, so there is no open transaction to roll back and Turso throws instead of silently no-oping.","triggerScenarios":"Calling conn.rollback() on a connection where autoCommit is true — typically a catch block that rolls back without ever having disabled autocommit, or after a pool reset autoCommit to true.","commonSituations":"catch (Exception e) { conn.rollback(); } error handling written before setAutoCommit(false) was added; unit tests reusing one connection across cases; pool reset code re-enabling autocommit before the application's rollback runs.","solutions":["Call conn.setAutoCommit(false) before executing statements that may need rollback","Guard the rollback: if (!conn.getAutoCommit()) { conn.rollback(); }","Keep setAutoCommit(false), the try/catch/rollback, and commit in one helper so they cannot drift apart"],"exampleFix":"// before\ntry (Statement st = conn.createStatement()) {\n  st.executeUpdate(\"UPDATE t SET a = 1\");\n} catch (SQLException e) {\n  conn.rollback(); // throws: still in autocommit mode\n}\n\n// after\nconn.setAutoCommit(false);\ntry (Statement st = conn.createStatement()) {\n  st.executeUpdate(\"UPDATE t SET a = 1\");\n  conn.commit();\n} catch (SQLException e) {\n  if (!conn.getAutoCommit()) conn.rollback();\n}","handlingStrategy":"validation","validationCode":"if (conn.getAutoCommit()) {\n  // nothing to roll back — statements committed individually\n} else {\n  conn.rollback();\n}","typeGuard":null,"tryCatchPattern":"try {\n  conn.rollback();\n} catch (SQLException e) {\n  if (\"Cannot rollback in autocommit mode.\".equals(e.getMessage())) {\n    // benign: no transaction was open\n  } else {\n    throw e;\n  }\n}","preventionTips":["Write rollback handlers together with setAutoCommit(false), never as standalone catch-block boilerplate","Guard every manual rollback with if (!conn.getAutoCommit())","Return pooled connections with transactions explicitly committed or rolled back"],"tags":["java","jdbc","transaction","autocommit","bindings"],"backgroundTag":"rollback-in-autocommit-mode","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}