问题 org.hibernate.ObjectNotFoundException:不存在具有给定标识符的行


我有一个问题,因为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错误还是我的不良做法?


7398
2018-01-17 12:45


起源



答案:


问题是尝试合并id = 2的Uvazek。 Hibernate看到它有一个密钥,但它不知道对象是否是脏的,所以不清楚是否应该进行SQL更新。

但由于密钥为2,Hibernate知道该对象必须存在于数据库中,因此它会尝试加载该对象,以便将其与刚刚在内存中接收的版本进行比较,以查看该对象是否有一些待处理的修改。被同步到数据库。

但是select没有返回结果,所以Hibernate有相互矛盾的信息:一方面数据库说对象不存在。另一方面,内存中的对象表示对象必须与键2一起存在。没有办法确定哪个是正确的,所以 ObjectNotFoundException 被抛出。

发生的事情是,在此版本之前,代码意外地基于同时修复的错误,因此这不再有效。

最佳做法是避免清除并仅在需要时将其用作内存优化,通过仅清除您不知道在同一会话中不会被修改或需要的对象,请查看 会话明确()被认为是有害的


11
2018-04-11 19:18



但为什么hibernate试图合并Uvazek? uvazeks集合上没有合并级联。是因为我尝试合并Ppv而且我在uvazeks集合上有fetch = FetchType.EAGER?在这种情况下,Hibernate需要让整个实体树持久化吗?这只是一个例子。我只使用clear()作为客户端服务器通信的模拟。在实践中它有点复杂。 - user3206615
生命救世主。我意外地在桌子上有一个空值。 - Saif


答案:


问题是尝试合并id = 2的Uvazek。 Hibernate看到它有一个密钥,但它不知道对象是否是脏的,所以不清楚是否应该进行SQL更新。

但由于密钥为2,Hibernate知道该对象必须存在于数据库中,因此它会尝试加载该对象,以便将其与刚刚在内存中接收的版本进行比较,以查看该对象是否有一些待处理的修改。被同步到数据库。

但是select没有返回结果,所以Hibernate有相互矛盾的信息:一方面数据库说对象不存在。另一方面,内存中的对象表示对象必须与键2一起存在。没有办法确定哪个是正确的,所以 ObjectNotFoundException 被抛出。

发生的事情是,在此版本之前,代码意外地基于同时修复的错误,因此这不再有效。

最佳做法是避免清除并仅在需要时将其用作内存优化,通过仅清除您不知道在同一会话中不会被修改或需要的对象,请查看 会话明确()被认为是有害的


11
2018-04-11 19:18



但为什么hibernate试图合并Uvazek? uvazeks集合上没有合并级联。是因为我尝试合并Ppv而且我在uvazeks集合上有fetch = FetchType.EAGER?在这种情况下,Hibernate需要让整个实体树持久化吗?这只是一个例子。我只使用clear()作为客户端服务器通信的模拟。在实践中它有点复杂。 - user3206615
生命救世主。我意外地在桌子上有一个空值。 - Saif


您还需要从Ppv中删除对Uvazek的引用。否则,当您将其关联并失败时,Hibernate会尝试恢复该关系,因为您删除了引用的Uvazek。

这也是为什么添加孤儿删除适合您的原因。


3
2018-04-11 19:35





我有相同的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);

删除这些孤立记录,提交更改并根据需要重新启动服务器。

这解决了我的例外。你也可以尝试一下。


1
2017-11-09 19:02