mybatis/mybatis-3 · error · RuntimeSqlException

Could not commit transaction. Cause: {}

Error message

Could not commit transaction. Cause: {}

What it means

ScriptRunner throws RuntimeSqlException from commitConnection() when Connection.commit() fails while running a SQL script with autoCommit disabled. ScriptRunner commits after each statement (or per its commitInterval), so any failure the driver reports at commit time — deferred constraint violation, lost connection, lock timeout — surfaces here. The original SQLException is chained as the cause.

Source

Thrown at src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java:193

  }

  private void setAutoCommit() {
    try {
      if (autoCommit != connection.getAutoCommit()) {
        connection.setAutoCommit(autoCommit);
      }
    } catch (Throwable t) {
      throw new RuntimeSqlException("Could not set AutoCommit to " + autoCommit + ". Cause: " + t, t);
    }
  }

  private void commitConnection() {
    try {
      if (!connection.getAutoCommit()) {
        connection.commit();
      }
    } catch (Throwable t) {
      throw new RuntimeSqlException("Could not commit transaction. Cause: " + t, t);
    }
  }

  private void rollbackConnection() {
    try {
      if (!connection.getAutoCommit()) {
        connection.rollback();
      }
    } catch (Throwable t) {
      // ignore
    }
  }

  private void checkForMissingLineTerminator(StringBuilder command) {
    if (command != null && command.toString().trim().length() > 0) {
      throw new RuntimeSqlException("Line missing end-of-line terminator (" + delimiter + ") => " + command);
    }
  }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Read the chained cause (getCause()) to find the real database error and fix that statement/constraint.
  2. If the script should not be committed piecemeal, call setAutoCommit(true) on the connection or scriptRunner.setAutoCommit(true) before runScript.
  3. Verify the connection is alive and not participating in an outer transaction that is already rollback-only.
  4. For lock timeouts, re-run when the contending transaction has finished or shorten the contending transaction.

Example fix

// before
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);
new ScriptRunner(conn).runScript(reader); // commit may fail

// after
Connection conn = dataSource.getConnection();
conn.setAutoCommit(true); // each statement autocommits; no manual commit path
new ScriptRunner(conn).runScript(reader);
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the connection can commit before running a long script
if (!conn.isValid(5)) {
  throw new IllegalStateException("Connection is not valid; cannot run script");
}

Try / catch

try {
  runner.runScript(reader);
} catch (RuntimeSqlException e) {
  Throwable cause = e.getCause(); // real SQLException
  log.error("Script commit failed: {}", cause.getMessage());
  // connection is unusable for the failed transaction; roll back / replace it
  safeRollback(conn);
}

Prevention

When it happens

Trigger: Calling scriptRunner.runScript(reader) (or executeScript) on a Connection with autoCommit=false where connection.commit() throws: deadlock/lock-wait timeout, deferred FK or unique constraint violation, connection already closed or broken, or XA transaction in a bad state.

Common situations: Running schema/data migration scripts (e.g. in tests or on startup) against HSQLDB/PostgreSQL/Oracle with manual transactions; DDL that implicitly fails at commit; scripts run inside an outer transaction that was already marked rollback-only.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/5280f73a136e9436. Report an issue: GitHub.