2014-01-17 27 views
10

我曾因爲Hibernate 4.1.8的問題導致以下異常:org.hibernate.ObjectNotFoundException:與給定的標識符的行存在

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [test.hibernate.TestPrepravkaOsobaSAdresou$Uvazek#2] 

我有兩個實體之間的簡單一對多關聯關係:

@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仍然有uvazek對分離的PPV集

org.hibernate.collection.internal.AbstractPersistentCollection.storedSnapshot 

相關信息。在以前的版本(< 4.1.8)這個工程。在這個簡單的例子中,我可以通過在pvv上設置的uvazeks上添加orphanRemoval=true來修復它,而不是刪除uvazek從pvv上設置的uvazeks中刪除它。

所以我的問題是:這是一個Hibernate錯誤還是我的壞習慣?

回答

10

問題是試圖合併id = 2的Uvazek。 Hibernate認爲它有一個鍵,但它不知道對象是否髒,所以不清楚是否應該進行SQL更新。

但是因爲鍵是2,Hibernate知道該對象必須存在於數據庫中,因此它會嘗試加載對象以便將其與它在內存中剛剛收到的版本進行比較,以查看該對象是否具有一些掛起的修改被同步到數據庫。

但是select返回沒有結果,所以Hibernate有矛盾的信息:一方面數據庫說對象不存在。另一方面,內存中的對象表示該對象必須以鍵2存在。無法確定哪個是正確的,因此拋出了ObjectNotFoundException

發生了什麼事情是,在此版本之前,代碼意外地基於一個同時得到修復的錯誤,所以這不再有效。

最好的做法是避免清楚,只有在需要作爲內存優化時才使用它,只需清除您知道不會在同一會話中修改或需要的對象,看看Is Session clear() considered harmful

+0

但爲什麼冬眠試圖合併Uvazek? uvazeks系列沒有合併級聯。是否因爲我嘗試合併Ppv,並且在uvazeks集合上有fetch = FetchType.EAGER?在這種情況下,我需要使用Ppv後,Hibernate需要使整個實體樹保持持久性?這只是一個例外。我只使用clear()作爲客戶端服務器通信的模擬。實際上它有點複雜。 – user3206615

+0

一個救世主。我意外地在桌子上留下了空虛的價值。 – Saif

3

您還需要從Ppv中刪除對Uvazek的引用。否則,Hibernate會在您將它合併回來並失敗時嘗試恢復關係,因爲您刪除了引用的Uvazek。

這也是爲什麼添加孤兒去除適合您的原因。

1

我有相同的Hibernate異常。

經過一段時間的調試後,我意識到問題是由孤兒子記錄引起的。

許多人抱怨,當他們搜索記錄時,它的存在。 我意識到這個問題不是因爲記錄的存在,而是因爲hibernate沒有在表格中找到它,而是因爲孤兒孩子的記錄。

這些記錄涉及到不存在的父母!

我所做的是找到對應於鏈接到Bean的表的外鍵引用。

要查找SQL開發人員

1.Save下面的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.增加用戶定義的擴展SQL開發

要找到所有的孤兒紀錄所提表

SELECT * FROM CHILD_TABLE 其中FOREIGNKEY不(SEL來自PARENT_TABLE的PRIMARYKEY);

刪除這些孤立記錄,提交更改並根據需要重新啓動服務器。

這解決了我的例外。你可以嘗試相同的。

相關問題