【问题标题】:Spring transaction management breaks hibernate cascadeSpring事务管理打破了休眠级联
【发布时间】:2011-02-15 23:34:18
【问题描述】:

我遇到了一个问题,将 Spring 的事务管理添加到应用程序会导致 Hibernate 抛出以下错误:

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)

我正在使用 Spring 2.5 和注释来实现这种管理。这是包含 saveNewReportCriteria 方法的类(从堆栈跟踪可以看出,它导致了错误)

@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;
    }
}

然后我将以下部分添加到我的配置文件中,以告诉 spring 我正在使用注释驱动的事务管理:

<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/>

我很确定取消引用错误是由于 Spring AOP 创建和使用的代理类来处理事务管理引起的,但我不知道如何修复它。

【问题讨论】:

    标签: hibernate transactions spring-mvc


    【解决方案1】:

    错误很可能不在该函数中,如果您仔细查看堆栈跟踪,您会发现错误是从代理的 saveNewReportCriteria 而不是您的类调用的。这可能是更早之前进行了更新或删除并且没有被休眠立即刷新到数据库的东西,因为它可以通过这种方式优化某些东西。

    找出发生了什么的一种方法是在每个删除/更新查询的末尾放置一个 .flush() ,这并不总是可取的,或者只是搜索您可能将处理臂设置为 null 的位置或 new List() - 清除休眠使用 list.clear() 上的列表;这将使休眠代理集合保持正确的类型。

    【讨论】:

    • 我确实看到错误来自代理,但我认为取消引用错误是由该代理的创建引起的。我已经修改了我的 bean 的treatmentArms 集合的设置器,因此它不应该被设置为 null 或一个新的列表。我的猜测是这个空/新分配是在创建代理类期间发生的,但我不确定如何避免这种情况。我会尝试将“flush”语句添加到我的 DAO 方法中。
    • 澄清一下,这里有 2 个代理在工作 - spring 围绕您的 HibernateReportCriteriaDao 类构建的代理以提供事务支持,以及 hibernate 在您的 @987654322 内部/周围使用的代理@ 班级。祝您使用 flush() 方法好运,它应该会告诉您问题出在哪里。
    • 添加 flush() 方法似乎对我没有任何作用。我之前忘了提到,即使抛出了这个异常,所有的数据都被持久化到了数据库中,这对我来说似乎是错误的。另外,如果我的帖子不清楚。在添加事务管理之前,同样的代码运行良好(因此,在添加 HibernateReportCriteriaDao 代理之前)
    • 那是最令人困惑的。您确定您没有在某处使用新列表调用 setTreatmentArms 吗?要替换所有值,您需要 .clear() 然后 .addAll() 到现有列表。我的做法是初始化变量列表中的列表(例如私有 List myList = new LinkedList)并且没有构造函数,然后永远不要在我的代码中使用休眠所需的 setMyList(..) 函数...
    • 感谢您对本 oedo 的帮助。我已经“解决”了这个问题,并且很想听听您是否对导致问题的原因有任何假设。
    【解决方案2】:

    我在一次保存父表和子表时遇到了同样的(全删除孤儿)问题。 解决方案:

    1. 先只保存父级
    2. 从父级获取子级并删除子表中的所有旧子级数据
    3. 向新的子数据添加父信息
    4. 添加新的子数据

    【讨论】:

      【解决方案3】:

      显然我的问题在于 saveNewReportCriteria 方法。删除第二个查询(对最大 ID 的 find() 调用)导致错误消失。我不知道为什么会这样。正如我之前提到的,在添加事务管理注释之前,此方法很好。如果有人知道这里发生了什么,我很想知道。

      【讨论】:

      • 酷,我希望这对你有用,但我强烈怀疑这个问题可能会再次困扰你 - 调用 find() 和添加事务不应该导致你得到的错误。无论如何祝你好运:)
      猜你喜欢
      • 2011-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 2010-11-14
      • 2012-08-08
      • 2010-12-31
      相关资源
      最近更新 更多