自Hibernate 4.1.8起出现了以下异常,我遇到了一个问题:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [test.hibernate.TestPrepravkaOsobaSAdresou$Uvazek#2]
我在两个实体之间有一个简单的OneToMany关联:
@Entity(name = "Ppv")
@Table(name = "PPV")
public static class Ppv {
@Id
Long ppvId;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "ppv")
Set<Uvazek> uvazeks = new HashSet<Uvazek>(0);
}
@Entity(name = "Uvazek")
@Table(name = "UVAZEK")
public static class Uvazek {
@Id
Long uvazekId;
@ManyToOne
@JoinColumn(name = "PPV_FXID")
Ppv ppv;
}
还有一个测试用例,其中我有一个Pv和两个Uvazek。当我加载和分离一个Pvv时,删除一个与已加载的Pvv相关的Uvazek并合并Ppv,我会得到一个异常(exception)。
jdbcTemplate.execute("insert into PPV values(1)");
jdbcTemplate.execute("insert into UVAZEK values(2, 1)");
jdbcTemplate.execute("insert into UVAZEK values(3, 1)");
Ppv ppv = (Ppv) getSession().get(Ppv.class, 1l);
getSession().clear();
getSession().delete(getSession().get(Uvazek.class, 2l));
getSession().flush();
getSession().merge(ppv);
getSession().flush(); //Causes the exception
在Ppv合并期间,Hibernate尝试加载已删除的Uvazek。即使删除了Uvazek,Hibernate仍然在其中包含有关它的信息
org.hibernate.collection.internal.AbstractPersistentCollection.storedSnapshot
在uvazek的Ppv上。在以前的版本(orphanRemoval=true来修复它,而不是删除uvazek,将其从Ppv上设置的uvazeks上删除。
所以我的问题是:这是Hibernate错误还是我的错误做法?
最佳答案
问题在于,试图将id = 2的Uvazek合并。 Hibernate看到它有一个 key ,但是它不知道对象是否脏了,因此不清楚是否应该进行SQL更新。
但是因为键是2,所以Hibernate知道对象必须存在于数据库中,因此它尝试加载该对象以便将其与刚刚在内存中接收到的版本进行比较,以查看该对象是否有待修改的对象。同步到数据库。
但是select不返回任何结果,因此Hibernate具有矛盾的信息:一方面数据库说该对象不存在。另一方面,内存中的对象表示该对象必须存在键2。由于无法确定哪个正确,因此会抛出ObjectNotFoundException
。
发生的事情是,在此版本之前,该代码意外地基于一个已修复的错误,因此不再有效。
最佳实践是避免清除并仅在需要时将其用作内存优化,方法是仅清除您知道在同一 session 中不再需要修改或不再需要的对象,请查看Is Session clear() considered harmful。