我有两种实体:事件和时间表。我试图修改它们,尽可能避免交易,以免在不必要的时间内锁定数据库。
所以而不是:
@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
来加载实体而没有明确地进行会话。
答案 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。