【问题标题】:Hibernate. When does same entity may be loaded twice in one session?休眠。同一实体何时可以在一个会话中加载两次?
【发布时间】:2014-01-03 14:05:05
【问题描述】:

有这样的问题。加载 2 个对象的集合(按主键,使用条件)。然后在循环中迭代它们。在处理第一个对象时,在离这个循环非常远的地方,通过与循环中的第二个对象相同的主键加载对象。在这里,我看到这两个对象的 System.identityHashCode() 是不同的。当处理循环中的第二个对象并尝试保存它时,我得到了异常:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

试图用简单的对象来模拟这个问题,加载,修改,再次通过 PK 加载,用不同的事务传播保存 - 我总是得到相同的对象实例...... 能否请您告知何时可以通过 PK 在同一会话加载中获取第二个对象实例?

【问题讨论】:

标签: java hibernate


【解决方案1】:

在我的情况下,问题是因为: 首先,我通过主键加载了一些实体“A”。 然后我使用一些标准加载了另一个实体“B”,这些标准通过 hbm 映射引用了这个相同的(通过 PK)实体“A”(例如 B->某个实体 C->A)并且休眠没有'不使用已经加载的'A'实体,而是加载或创建它(我在实体'A'构造函数中放置了断点),因此在单个会话中,我们有2个具有相同PK但不同实例的实体。试图保存实体“A”我们得到异常“NonUniqueObjectException”。 加载实体“B”距离非常远,在某些情况下可以重现和识别问题。 为了更快地找到这些地方,可以轻松地在“NonUniqueObject”构造函数中放置断点,然后找到第二次加载这个实体的人。 顺便说一句,在我加载实体“B”之后,我没有尝试调用 B->C->A、lazy='proxy' 或根本没有lazy,这意味着每个请求都加载 C。对我来说有些奥秘......

【讨论】:

    【解决方案2】:

    使用单个主键字段(例如 String 或 Integer)实现 equals() 和 hashcode() 的简单方法如下:

    public boolean equals(Object obj) {
       if (obj == null) { return false; }
       if (obj == this) { return true; }
       if (obj.getClass() != getClass()) {
         return false;
       }
       ThisClass that = (ThisClass) obj;
       return this.id.equals( that.id );
    }
    public int hashCode() {
        returns id.hashCode();
    }
    

    对于复合键,您需要使用如下代码:

    http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/HashCodeBuilder.html

    http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/EqualsBuilder.html

    【讨论】:

    • 我认为在实体类上实现equals和hashCode是一种反模式?无论如何,一个持久化上下文每个 PK 最多维护一个托管实体,因此覆盖这些方法只会使开发人员感到困惑。
    猜你喜欢
    • 2018-11-30
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    • 2014-09-12
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    相关资源
    最近更新 更多