hibernate/hibernate-orm · error · TransactionRequiredException

No active transaction for update or delete query

Error message

No active transaction for update or delete query

What it means

Same guard as error 1547 (checkTransactionNeededForUpdateOperation), invoked from the bulk-statement path: executeUpdate() on an HQL/SQL/criteria update or delete query requires an active transaction unless hibernate.allow_update_outside_transaction is true. The message here names the caller's context: 'No active transaction for update or delete query'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java:1318

		return factory.getServiceRegistry()
				.requireService( ConfigurationService.class )
				.getSettings();
	}

	protected void initializeCurrentChangesetIdentifier() {
		currentChangesetId = generateCurrentChangesetIdentifier();
	}

	protected void clearTransactionStartInstant() {
		currentChangesetId = null;
		currentChangesetContext = null;
	}

	@Override
	public void checkTransactionNeededForUpdateOperation(@Nonnull String exceptionMessage) {
		if ( !factoryOptions.isAllowOutOfTransactionUpdateOperations()
				&& !isTransactionInProgress() ) {
			throw new TransactionRequiredException( exceptionMessage );
		}
	}

	private boolean isTransactionAccessible() {
		// JPA requires that access not be provided to the transaction when using JTA.
		// This is overridden when SessionFactoryOptions isJtaTransactionAccessEnabled() is true.
		return factoryOptions.isJtaTransactionAccessEnabled() // defaults to false in JPA bootstrap
			|| !factoryOptions.getJpaCompliance().isJpaTransactionComplianceEnabled()
			|| !factory.transactionCoordinatorBuilder.isJta();
	}

	@Override
	@Nonnull
	public Transaction getTransaction() throws HibernateException {
		if ( !isTransactionAccessible() ) {
			throw new IllegalStateException(
					"Transaction is not accessible when using JTA with JPA-compliant transaction access enabled"
			);

View on GitHub (pinned to fad1729dce)

Solutions

  1. Begin a transaction before executeUpdate(): @Transactional on the method, or session.beginTransaction()/TransactionTemplate.
  2. If you truly want auto-commit bulk DML, set hibernate.allow_update_outside_transaction=true and accept the loss of atomicity.
  3. Check for proxy/self-invocation issues that silently dropped the transaction.

Example fix

// before
int n = em.createQuery("delete from AuditLog a where a.created < :d")
          .setParameter("d", cutoff).executeUpdate(); // throws
// after
@Transactional
public int purgeBefore(Instant cutoff) {
    return em.createQuery("delete from AuditLog a where a.created < :d")
             .setParameter("d", cutoff).executeUpdate();
}
Defensive patterns

Strategy: validation

Validate before calling

Transaction tx = session.isTransactionInProgress() ? null : session.beginTransaction();
try {
    int n = session.createMutationQuery("delete from AuditLog a where a.created < :d")
                   .setParameter("d", cutoff).executeUpdate();
    if (tx != null) tx.commit();
    return n;
} catch (RuntimeException e) {
    if (tx != null) tx.rollback();
    throw e;
}

Prevention

When it happens

Trigger: session.createMutationQuery("update Stock s set ...").executeUpdate(), createNativeQuery("delete from log_table").executeUpdate(), or criteria update/delete executed while isTransactionInProgress() is false.

Common situations: Bulk maintenance/cleanup jobs without @Transactional; test data deletion outside a transaction; refactoring a select query into an update but keeping the non-transactional context; Spring method-level security or AOP ordering hiding the missing transaction.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/09efbfe480429275. Report an issue: GitHub.