hibernate/hibernate-orm · critical · TransactionException
Unable to commit against JDBC Connection
Error message
Unable to commit against JDBC Connection
What it means
Commit-time failure: the logical connection's Connection.commit() threw an SQLException. Hibernate sets status FAILED_COMMIT, attempts a last-ditch rollback() (whose own failure is attached as a suppressed exception), then wraps the commit error in this TransactionException. Because the connection died mid-commit, whether the data actually committed is indeterminate and must be verified before retrying.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/AbstractLogicalConnectionImplementor.java:110
status = TransactionStatus.COMMITTED;
CONNECTION_LOGGER.transactionCommittedViaConnectionCommit();
}
catch (SQLException e) {
// commit failed, the current status of the
// transaction is ambiguous
status = TransactionStatus.FAILED_COMMIT;
// make a last ditch attempt to roll it back
try {
getConnectionForTransactionManagement().rollback();
status = TransactionStatus.ROLLED_BACK;
}
catch (SQLException e2) {
e.addSuppressed( e2 );
JDBC_LOGGER.encounteredFailureRollingBackFailedCommit( e2 );
// at this point we can't really know for
// sure what happened to the transaction
}
throw new TransactionException( "Unable to commit against JDBC Connection", e );
}
}
protected void afterCompletion() {
// by default, nothing to do
}
protected void resetConnection(boolean initiallyAutoCommit) {
try {
if ( initiallyAutoCommit ) {
CONNECTION_LOGGER.reenablingAutoCommitAfterJdbcTransaction();
getConnectionForTransactionManagement().setAutoCommit( true );
status = TransactionStatus.NOT_ACTIVE;
}
}
catch ( Exception e ) {
CONNECTION_LOGGER.couldNotReEnableAutoCommit( e );
}View on GitHub (pinned to fad1729dce)
Solutions
- Read the cause SQLException's SQLState: 08xxx (connection) and 40001/40P01/55P03 (deadlock/lock timeout) are transient; constraint classes (23xxx) are permanent data problems
- Before retrying, verify whether the work actually committed (re-query the data, check in-doubt/XA recovery logs) to avoid duplicate effects
- For transient classes, retry the entire transaction from the beginning with a new Session and idempotent logic
- Increase driver/pool timeouts (socketTimeout, connectionTimeout) if legitimate commits are long
Example fix
// before
em.getTransaction().commit(); // TransactionException: Unable to commit against JDBC Connection
// after
try {
em.getTransaction().commit();
} catch (org.hibernate.TransactionException e) {
SQLException sql = findSqlException(e);
String state = sql == null ? null : sql.getSQLState();
boolean transientFailure = state != null
&& (state.startsWith("08") || "40001".equals(state) || "40P01".equals(state) || "55P03".equals(state));
if (transientFailure) { /* verify outcome, then retry unit of work with new EntityManager */ }
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// before committing, confirm the connection is still usable em.unwrap(org.hibernate.Session.class).doReturningWork(c -> c.isValid(5));
Type guard
static SQLException findSqlException(Throwable t) {
for (Throwable c = t; c != null; c = c.getCause()) {
if (c instanceof SQLException s) return s;
}
return null;
} Try / catch
try {
tx.commit();
} catch (org.hibernate.TransactionException e) {
SQLException sql = findSqlException(e);
String s = sql == null ? null : sql.getSQLState();
boolean transientFailure = s != null
&& (s.startsWith("08") || "40001".equals(s) || "40P01".equals(s) || "55P03".equals(s));
// transient: FIRST verify whether the work actually committed (re-query),
// then retry the idempotent unit of work on a new EntityManager; otherwise rethrow
} Prevention
- Keep transactions short so commit latency stays well under any timeout
- Make units of work idempotent so a retry after an in-doubt commit is safe
- Set driver/pool timeouts (socketTimeout, connectionTimeout) above worst-case commit duration
- Validate deferrable-constraint data before commit rather than relying on commit-time checks
When it happens
Trigger: tx.commit() on a resource-local session where Connection.commit() throws: deferred/deferrable constraint violations surfacing only at commit, deadlock or lock-wait timeout detected at commit time, connection reset between flush and commit, or a socket/stream timeout on a long-running commit.
Common situations: Network blip exactly at commit; long transactions exceeding driver socketTimeout; PostgreSQL deferrable constraints failing at COMMIT; connection killed by an LB idle policy or DBA mid-commit.
Related errors
- Transaction not successfully started
- JDBC begin transaction failed:
- Unable to rollback against JDBC Connection
- JDBC driver does not support named parameters for setArray.
- Newer version [" + latestVersion + "] of entity [" + infoStr
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/90c4d019d795c626.
Report an issue: GitHub.