【问题标题】:Hibernate lazy initialization helpHibernate 延迟初始化帮助
【发布时间】:2009-09-21 16:40:05
【问题描述】:

我在尝试使用休眠删除时遇到问题。当我尝试删除时,我得到一个异常,说孩子存在并且存在 FK 违规。我也想删除孩子,但删除似乎不是级联的。在尝试解决这个问题大约一周后,我读到我应该使用 HibernateInterceptor 来保持会话打开,以便可以加载孩子。当我现在尝试执行此操作时,出现以下错误:

Failed to load portlet com.blah.blah.CommunicationsPortlet: java.lang.ClassCastException: $Proxy27 incompatible with com.blah.blah.HibernateCommunicationsDAOImpl

这是我的映射文件的摘录:

<set name="communicationCountries" inverse="true" cascade="all,delete-orphan">
<key column="COM_ID" not-null="true" on-delete="cascade" />
<one-to-many class="com.blah.blah.CommunicationCountry"/>
</set>

以下是应用程序上下文的摘录:

<bean id="hibernateCommunicationsDAOImplTarget"
class="com.blah.blah.dao.impl.HibernateCommunicationsDAOImpl">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>

<bean id="hibernateCommunicationsDAOImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="hibernateCommunicationsDAOImplTarget"/></property>
<property name="proxyInterfaces">
<value>com.blah.blah.dao.CommunicationsDAO</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>

这是我的 DAO 中的方法:

public void deleteCommunication(Integer id) throws DataAccessException
{
HibernateTemplate hibernate = getHibernateTemplate();
Communication existing = (Communication)hibernate.get(Communication.class, id);
hibernate.initialize( existing.getCommunicationCountries());
hibernate.delete(existing);
} 

我真的不知道我做错了什么。我没有一个非常复杂的模式,只有一个导致孩子(国家)的表。有什么想法可以解决这个问题吗?

【问题讨论】:

  • 您是否在尝试删除实体之前从 dao 加载实体?即 MyForm form = formdao.getForm();然后你做你的 form.delete()。
  • 抱歉,我浏览了您代码中的 hibernate.get。

标签: java database hibernate spring spring-aop


【解决方案1】:

如果您只想删除父项和子项,则不需要加载子项集合。你甚至不需要get()父,使用load()就足够了:

public void deleteCommunication(Integer id) throws DataAccessException {
  HibernateTemplate hibernate = getHibernateTemplate();
  Communication existing = (Communication) hibernate.load(Communication.class, id);
  hibernate.delete(existing);
}

当然,这假设适当的映射/级联到位。除了&lt;key ... on-delete="cascade"/&gt; 设置外,您显示的设置映射摘录是可以的。由于以下几个原因,这相当棘手:

  1. 您的数据库必须支持它并且您的架构必须定义它。如果不是这种情况,您会收到错误消息。
  2. 如果 cascade 设置为“ALL”,您将不会通过此设置获得任何性能改进,因为 Hibernate 会仍然加载每个子实体以检查进一步的关联。您需要将级联设置为“保存更新”才能使其正常工作,这会对托管生命周期的父子关系产生副作用。

因此,我建议暂时删除on-delete="cascade",并且在您完全理解所有含义之前不要使用它。

您提到的 HibernateInterceptor 与所有这些无关(当然与您编写的 delete() 方法无关);它是open-session-in-view 与 UI 层通信方法的一部分。

以下是解决上述所有问题的方法:

  1. 暂时摆脱 HibernateInterceptor。
  2. 编写单元测试以在一个事务中创建父/子,提交它,在第二个事务中删除它们,提交它。
  3. 如果 (2) 不起作用,您的映射和/或架构有问题。把两个都贴在这里,我去看看。
  4. 如果 (2) 有效并且您上面的 delete() 方法无效,则您的代码中调用 delete() 的地方存在问题。也许您正在加载相同的 Communication 实例并覆盖其 communicationCountries 集合。

【讨论】:

  • 我不知道为什么,但这对我有用。很奇怪,这就是我之前所拥有的,只是我使用了 .get() 而不是 .load()。非常感谢您的帮助,在想知道为什么这不起作用一周后,我终于可以放松了
  • get() vs load() 在错误方面应该无关紧要。删除 on-delete=cascade 会:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
相关资源
最近更新 更多