我有一个问题,因为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;
}
和一个测试案例,我有一个Ppv和两个Uvazek。当我加载和分离Ppv时,删除一个与加载的Ppv相关联的Uvazek并合并Ppv我得到一个异常。
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上。在以前的版本(<4.1.8)中,这可行。在这个简单的例子中,我可以通过添加来修复它 orphanRemoval=true
在uvazeks上设置Ppv而不是删除uvazek从pvv上设置的uvazeks中删除它。
所以我的问题是:这是一个Hibernate错误还是我的不良做法?
问题是尝试合并id = 2的Uvazek。 Hibernate看到它有一个密钥,但它不知道对象是否是脏的,所以不清楚是否应该进行SQL更新。
但由于密钥为2,Hibernate知道该对象必须存在于数据库中,因此它会尝试加载该对象,以便将其与刚刚在内存中接收的版本进行比较,以查看该对象是否有一些待处理的修改。被同步到数据库。
但是select没有返回结果,所以Hibernate有相互矛盾的信息:一方面数据库说对象不存在。另一方面,内存中的对象表示对象必须与键2一起存在。没有办法确定哪个是正确的,所以 ObjectNotFoundException
被抛出。
发生的事情是,在此版本之前,代码意外地基于同时修复的错误,因此这不再有效。
最佳做法是避免清除并仅在需要时将其用作内存优化,通过仅清除您不知道在同一会话中不会被修改或需要的对象,请查看 会话明确()被认为是有害的。
问题是尝试合并id = 2的Uvazek。 Hibernate看到它有一个密钥,但它不知道对象是否是脏的,所以不清楚是否应该进行SQL更新。
但由于密钥为2,Hibernate知道该对象必须存在于数据库中,因此它会尝试加载该对象,以便将其与刚刚在内存中接收的版本进行比较,以查看该对象是否有一些待处理的修改。被同步到数据库。
但是select没有返回结果,所以Hibernate有相互矛盾的信息:一方面数据库说对象不存在。另一方面,内存中的对象表示对象必须与键2一起存在。没有办法确定哪个是正确的,所以 ObjectNotFoundException
被抛出。
发生的事情是,在此版本之前,代码意外地基于同时修复的错误,因此这不再有效。
最佳做法是避免清除并仅在需要时将其用作内存优化,通过仅清除您不知道在同一会话中不会被修改或需要的对象,请查看 会话明确()被认为是有害的。
您还需要从Ppv中删除对Uvazek的引用。否则,当您将其关联并失败时,Hibernate会尝试恢复该关系,因为您删除了引用的Uvazek。
这也是为什么添加孤儿删除适合您的原因。
我有相同的Hibernate异常。
经过一段时间的调试后,我意识到问题是由Orphan子记录引起的。
正如许多人在抱怨,当他们搜索记录时,它就存在了。
我意识到问题不是因为记录的存在而是休眠没有在表中找到它,而是由于Orphan子记录。
记录中提到了不存在的父母!
我所做的是,找到对应于链接到Bean的表的外键引用。
在SQL开发人员中查找外键引用
1.将以下XML代码保存到文件中(fk_reference.xml)
<items>
<item type="editor" node="TableNode" vertical="true">
<title><![CDATA[FK References]]></title>
<query>
<sql>
<![CDATA[select a.owner,
a.table_name,
a.constraint_name,
a.status
from all_constraints a
where a.constraint_type = 'R'
and exists(
select 1
from all_constraints
where constraint_name=a.r_constraint_name
and constraint_type in ('P', 'U')
and table_name = :OBJECT_NAME
and owner = :OBJECT_OWNER)
order by table_name, constraint_name]]>
</sql>
</query>
</item></items>
2.将USER DEFINED扩展添加到SQL Developer
在所有引用的表中查找孤立记录
从CHILD_TABLE中选择*
FOREIGNKEY不在的地方(从PARENT_TABLE中选择PRIMARYKEY);
删除这些孤立记录,提交更改并根据需要重新启动服务器。
这解决了我的例外。你也可以尝试一下。