After further investigation it seems that this is being caused by the LogicalConnectionManagedImpl#afterCompletion() method, which in turn calls its super class implementation of resetConnection() in AbstractLogicalConnectionImplementor#resetConnection() method.
protected void afterCompletion() {
resetConnection( initiallyAutoCommit );
initiallyAutoCommit = false;
afterTransaction();
}
In resetConnection(), the connection status is set to NOT_ACTIVE:
protected void resetConnection(boolean initiallyAutoCommit) {
try {
if ( initiallyAutoCommit ) {
log.trace( "re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction" );
getConnectionForTransactionManagement().setAutoCommit( true );
status = TransactionStatus.NOT_ACTIVE;
}
}
catch ( Exception e ) {
log.debug(
"Could not re-enable auto-commit on JDBC Connection after completion of JDBC-based transaction : " + e
);
}
}
This is causing the EntityManager to report that it is not joined to a transaction, even though there is an active transaction that Spring is managing. This causes any update statement made at this point to fail because Hibernate thinks that there is not an active transaction.
There is a flag which I can supply in my persistence.xml files:
<property name="hibernate.allow_update_outside_transaction" value="true"/>
But this seems rather dangerous to me as the JPA spec disallows this behavior for good reasons.
This change in Hibernate’s resetConnection() method is clearly the cause of the problem but I can’t determine why this is being invoked at this point. Spring still believes that there is an active transaction. While my SQL work is being performed in an afterCommit synchronization there really should be no issue as the transaction is still active.
Is there any way around this issue other than using the property in persistence.xml?