I'm having a problem where the addition of spring's transaction management to an application causes Hibernate to throw the following error:
org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: org.fstrf.masterpk.domain.ReportCriteriaBean.treatmentArms
org.hibernate.engine.Collections.processDereferencedCollection(Collections.java:96)
org.hibernate.engine.Collections.processUnreachableCollection(Collections.java:39)
org.hibernate.event.def.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:218)
org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:77)
org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
org.springframework.orm.hibernate3.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:135)
org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:72)
org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:905)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:715)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
$Proxy92.saveNewReportCriteria(Unknown Source)
org.fstrf.masterpk.domain.logic.MasterPkFacade.saveNewReportCriteria(MasterPkFacade.java:134)
org.fstrf.masterpk.controllers.ReportCriteriaController.setupReportType(ReportCriteriaController.java:302)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:585)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:413)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:134)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:310)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:297)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
I'm using Spring 2.5 and annotations to implement this management. Here is the class containing the saveNewReportCriteria method (which, as can be seen by the stack trace, is causing the error)
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false)
public class HibernateReportCriteriaDao implements ReportCriteriaDao{
private HibernateTemplate hibernateTemplate;
public Integer saveNewReportCriteria(ReportCriteriaBean reportCriteria) {
hibernateTemplate.save(reportCriteria);
List<Integer> maxIdList = hibernateTemplate.find("SELECT max(id) from ReportCriteriaBean");
logger.info("ID of newly saved list is: " + maxIdList.get(0));
return maxIdList.get(0);
}
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
}
Then I added the following sections to my configuration files to tell spring that I am using annotation driven transaction management:
<bean id="actgDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/actg" />
<property name="resourceRef" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="actgDataSource" />
</bean>
<tx:annotation-driven/>
I'm pretty sure that the de-referencing error is being caused due to the proxy class that Spring AOP creates and uses in order to handle transaction management, but I have no idea how I'd go about fixing it.
I got the same (all-delete-orphan) problem while saving the parent and child tables at a time. Solution:
the error might well NOT be in that function, if you look carefully at the stack trace you'll see that the error is being called from the PROXY's saveNewReportCriteria and not your class's. this is likely something earlier that did an update or delete and wasn't flushed immediately to the db by hibernate because it can optimise certain things that way.
one way to find out what's happening is to put a .flush() at the end of every delete/update query, which isn't always desirable, or alternatively just do a search for where you might be setting treatmentArms to null or a new List() - to clear a list on hibernate use list.clear(); which will keep the hibernate-proxied collection the correct type.
Apparently my problem did lie with the saveNewReportCriteria method. Removal of the second query (the find() call for the maximum ID) caused the error to go away. I have no idea why this is the case. As I mentioned earlier, this method was fine prior to the addition of the transaction management annotations. If anyone knows what is going on here I'd love to find out.