Description
Allan Jones opened SPR-15334 and commented
My environment:
Using spring with JPA + JTA and Hibernate 5.2.8.Final + Envers
The problem is that Springframework ORM (JPA subpackage) closes the entity manager too early (During ```java
triggerBeforeCompletion(status)
When the Hibernate envers listeners are triggered (during ```java
doCommit(status)
``` step), the entity manager is already closed.
Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: The transaction was set to rollback only
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1026)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at com.myapp.services.MyService.reproduceIssue(MyService.java:40)
at com.myapp.App.main(App.java:12)
Caused by: javax.transaction.RollbackException: The transaction was set to rollback only
at com.atomikos.icatch.jta.TransactionImp.rethrowAsJtaRollbackException(TransactionImp.java:66)
at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:207)
at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:433)
at com.atomikos.icatch.jta.J2eeUserTransaction.commit(J2eeUserTransaction.java:94)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1023)
... 4 more
Caused by: java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:332)
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:126)
at org.hibernate.internal.SessionImpl.guessEntityName(SessionImpl.java:2228)
at org.hibernate.envers.event.spi.BaseEnversEventListener.addCollectionChangeWorkUnit(BaseEnversEventListener.java:107)
at org.hibernate.envers.event.spi.BaseEnversEventListener.generateBidirectionalCollectionChangeWorkUnits(BaseEnversEventListener.java:76)
at org.hibernate.envers.event.spi.EnversPostInsertEventListenerImpl.onPostInsert(EnversPostInsertEventListenerImpl.java:49)
at org.hibernate.action.internal.EntityInsertAction.postInsert(EntityInsertAction.java:164)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:131)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:586)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:460)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1428)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:484)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3190)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2404)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:320)
at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
at com.atomikos.icatch.jta.Sync2Sync.beforeCompletion(Sync2Sync.java:50)
at com.atomikos.icatch.imp.TransactionStateHandler.notifyBeforeCompletion(TransactionStateHandler.java:261)
at com.atomikos.icatch.imp.TransactionStateHandler.commit(TransactionStateHandler.java:236)
at com.atomikos.icatch.imp.CompositeTransactionImp.doCommit(CompositeTransactionImp.java:288)
at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:337)
at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:191)
... 7 more
WIth some analysis I found that
TransactionalEntityManagerSynchronization (org.springframework.orm.jpa.EntityManagerFactoryUtils) closes the entityManager too early and there's no way to configure or change the following:
```java
org.springframework.transaction.support.ResourceHolderSynchronization<H, K>
protected boolean shouldReleaseBeforeCompletion() {
return true;
}
In hibernate 4.x there's no problem because the EntityManager and hibernate Session are two different instances and closing the entity manager won't always close the hibernate session. In hibernate 5.2.x they are the same instance.
I created a small setup where I can reproduce the issue. Please find it attached.
Main class: ```java
com.myapp.App
Affects: 4.3.7
Attachments:
- MyApp.zip (11.71 kB)
Issue Links:
- Support for Hibernate ORM 5.2 [SPR-14327] #18899 Support for Hibernate ORM 5.2