【问题标题】:Hibernate 4 composite-id NonUniqueObjectExceptionHibernate 4 复合 ID NonUniqueObjectException
【发布时间】:2014-11-25 11:55:53
【问题描述】:

将我的项目从 Hibernate 3 升级到 Hibernate 4 时抛出了 NonUniqueObjectException。 我为测试目的创建了最小的 Hibernate 4 项目,并通过以下方式设法重现此异常:

  • 具有实体 House,以及另一个具有包含 House 实体的复合 id 的实体 Door

    <class dynamic-insert="true" dynamic-update="true" name="entity.Door" select-before-update="true" table="DOOR">
    <composite-id name="id" class="DoorHousePK">
        <key-many-to-one class="entity.House" column="HOUSEID" name="house"/>
        <key-property column="DOORID" name="doorId" type="string"/>
    </composite-id>
    

  • 然后在同一个事务中获取 House,然后通过复合 id 获取 Door:

(门)session.get(Door.class, doorHousePK)

这是 House 的 hbm 文件:

<class dynamic-insert="true" dynamic-update="true" name="entity.House" select-before-update="true" table="HOUSE">
        <id column="ID" name="id" type="int"/>
        <property column="squarefeet" name="squareFeet" not-null="false" type="int"/>
        <property column="address" length="255" name="address" not-null="false" type="string"/>
        <property column="color" length="32" name="color" not-null="false" type="string"/>
        <property column="description" name="description" not-null="false" type="materialized_clob"/>
    </class>

,以及错误的堆栈跟踪:

INFO: HHH000327: Error performing load command : org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [entity.House#1]
Exception in thread "main" org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [entity.House#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:617)
    at org.hibernate.event.internal.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:74)
    at org.hibernate.event.internal.DefaultLockEventListener.onLock(DefaultLockEventListener.java:95)
    at org.hibernate.internal.SessionImpl.fireLock(SessionImpl.java:774)
    at org.hibernate.internal.SessionImpl.fireLock(SessionImpl.java:767)
    at org.hibernate.internal.SessionImpl.access$1800(SessionImpl.java:176)
    at org.hibernate.internal.SessionImpl$LockRequestImpl.lock(SessionImpl.java:2491)
    at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.addKeyManyToOnesToSession(EntityLoadQueryDetails.java:263)
    at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:247)
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:129)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
    at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:503)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:468)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:213)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
    at org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:176)
    at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2551)
    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:955)

当将此最小项目恢复到 Hibernate 3 时,异常消失了,一切正常。

Hibernate 3 和 Hibernate 4 在复合 ID 处理方面有什么区别? 如何在 Hibernate 4 中完成这项工作?

【问题讨论】:

    标签: java spring hibernate jpa


    【解决方案1】:

    我最近从 hibernate 3 迁移到 4,其中两个表具有复合 id 并通过复合外键相互关联。完全相同的配置在两个版本中运行良好。因此,就复合 ID 功能的基本概念而言,没有区别。

    您应该启用休眠 API 的调试,即在日志属性文件中将 org.hibernate.* 的调试级别设置为 DEBUG,以查看正在触发哪些 SQL。这将帮助您查看 hibernate 是否触发了任何其他/意外的 SQL。

    【讨论】:

    • 为此我将 min 项目附加到票证上,当在 Hibernate 3 和 4 之间切换时,该问题在这个最小项目中重现。这是附加 min 项目的票证hibernate.atlassian.net/browse/HHH-9521
    • 我查看了您的代码。您正在加载具有相同 id 的父对象两次。一次在 Hib4Min.java main 方法中,然后在 ChildService 的rerepeatNonUniqueObjectException 方法中。您可以安全地注释掉后一个调用(ChildService.java 中的一个),因为您不需要它。如果您需要 Parent 对象,您可以从 ChildParentPK 的 getParent 方法中获取。一旦你注释掉这个调用,你的代码就会运行良好。我还没有尝试在 hibernate 3 中运行。
    • 实际上导致问题的原因是 ChildService 的reproduceNonUniqueObjectException 中的两个调用:-getParentById 和-getChildById。 getParentById 的第一次调用与问题无关。问题是这另外两个调用在同一个事务中。我的项目代码中有类似的情况,我们在同一事务中获取父对象,然后是子对象。这是在 Hibernate 3 中工作,而不是在 Hibernate 4 中工作。所以我想知道为什么这在 H​​ibernate 3 中工作并在 Hibernate 4 中抛出异常。
    【解决方案2】:

    确保您的实体以及构成复合主键的对象具有 hashCode() 和 equals() 的适当实现。我似乎记得 Hibernate 3 和 4 之间的哈希码使用和/或对象相等性检查存在一些潜在的变化。

    【讨论】:

      猜你喜欢
      • 2011-04-02
      • 2015-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-27
      相关资源
      最近更新 更多