Hibernate:实体副本[Event#XXX]已经分配给不同的实体[Event#XXX]

时间:2014-03-13 22:33:03

标签: java spring hibernate jpa

我有两种实体:事件和时间表。我试图修改它们,尽可能避免交易,以免在不必要的时间内锁定数据库。

所以而不是:

@Transactional
public void modify() {
    Event event = em.find(...);
    //... something that might take a long time
    event.addSchedule(schedule);
    em.flush();
}

我正在努力:

public void modify() {
    Event event = em.find(...);
    //... something that might take a long time
    event.addSchedule(schedule);
    repository.merge(event);
}

...
@Transactional
public void merge(Event event) {
    em.merge(event);
    em.flush();
}

问题是像这样我得到例外:An entity copy [Event#XXX] was already assigned to a different entity [Event#XXX]。我不复制实体,也不做任何意外的事情。

另外,据说有必要正确实现equals()和hashCode()方法。我有它们,但是当我研究堆栈跟踪时,似乎实体不是通过equals比较,也不是hashCode,它们与==进行比较,如下所示:http://grepcode.com/file/repo1.maven.org/maven2/org.hibernate/hibernate-core/4.1.3.Final/org/hibernate/event/internal/EventCache.java#62

他们使用IdentityHashMap,专门使用==

那我在哪里可以找到问题?我已经尝试了从4.1.7到当前4.3.4的休眠,并且我使用hibernate.enable_lazy_load_no_trans来加载实体而没有明确地进行会话。

2 个答案:

答案 0 :(得分:2)

我设法通过在已发布的类的所有关系上将Cascade类型从All更改为Persist来解决此问题。

答案 1 :(得分:0)

Event的equals / hashcode的实现似乎存在问题:

  

实体副本[事件#1000]已分配给其他实体[事件#1001]

实体副本是内存中的Java对象,它对应于数据库中的实体。内存中可能有多个副本指向同一个DB记录。

消息说有两个Event个对象具有不同的数据库标识符(@Id列),所以从数据库身份(obj1.getId().equals(obj2.getId()))的角度来看是不一样的

但是从Java等价(obj1.equals(obj2))的角度来看,它们被认为是相同的。但是数据库和内存中的两个对象不能不同,这会导致错误。

解决方案是修复equals / hashcode实现,有关问题的详细信息,请参阅此answer,有关实现Hibernate实体的equals / hascode的详细信息,请参阅此page