Hibernate Session篇--org.hibernate.NonUniqueObjectException分析及解決

1 問題描述:

用hibernate做修改和刪除的時候,有時候會遇到 org.hibernate.NonUniqueObjectException 異常,

a different object with the same identifier value was already associated with the session

可以解釋爲 有一個具有相同值的不同對象已經與和 session 相關聯

google了哈,http://www.blogjava.net/Unmi/archive/2007/08/10/135771.html 的辦法是:

重現以上錯誤的代碼如下(去除了事物控制的代碼行):

1. Session session = HibernateSessionFactory.getSession();
2.
3. // 加載OID爲1L的對象,會被放在session緩存中
4. LoanDetail detail = (LoanDetail)session.get(LoanDetail.class,1L);
5.
6. // new 一個OID也爲1L的臨時對象
7. LoanDetail newDetail = new LoanDetail(1L);
8. ewDetail.setSubjectId(1000L);
9.
10. // 持久化一個臨時對象,試圖放在session的緩存中,因OID衝突出現異常
11. session.save(newDetail);
12.
13. // 執行saveOrUpdate同樣會出現以上的異常
14. // session.saveOrUpdate(newDetail);

2 解決方法:
1) 如果用的 hibernate 2, 需要在get/load/query到持久化對象,賦上新的屬性值,再 save/update/saveOrupdate.
對以上代碼就是:不能 new 一個session中已存在OID的對象,直接
detail.setSubjectId(1000L);
session.save(detail);
session.save()一個持久化對象時,會轉化成update調用。

2) 使用 hibernate 3 的 merge 方法. session.merge(newDetail)即可,它會在 session 緩存中找到持久化對象,把新對象的屬性賦過去,再保存原session中的持久化對象。
如果在session或數據庫中沒有的對象,用merge方法的話,它也能夠幫你把記錄 insert 到表中,相當於 save 方法。

3)原作者的辦法:

     a. 在 session.update/delete/saveOrUpdate 前,先 session.clear();

     b. 在 session.update/delete/saveOrUpdate 後,關閉session:session.close();

4) evict()

不管何時你傳遞一個對象給save(), update()或者 saveOrUpdate() ,或者不管何時你使用load(), find(), iterate()或者filter()取得一個對象的時候,該對象被加入到Session的內部緩存中。當後繼的flush()被調用時,對象的狀態會和數據庫進行同步。如果你在處理大量對象並且需要有效的管理內存的時候,你可能不希望發生這種同步,evict()方法可以從緩存中去掉對象和它的集合。

Iterator cats = sess.iterate("from eg.Cat as cat"); //a huge result set
while ( cats.hasNext() ) {
     Cat cat = (Cat) iter.next();
     doSomethingWithACat(cat);
     sess.evict(cat);
}
Session也提供了一個contains()方法來判斷是否一個實例處於這個session的緩存中。

要把所有的對象從session緩存中完全清除,請調用Session.clear()。

For the JVM-level JCS cache, there are methods defined on SessionFactory for evicting the cached state of an instance, entire class, collection instance or entire collection role.

對於第二層緩存來說,在SessionFactory中定義了一些方法來從緩存中清除一個實例、整個類、集合實例或者整個集合。

3 原因分析

       這個異常困擾了我一個星期,冥思不得其解,且在網上搜的方法都是“點到爲止”,所以看了依然一頭霧水。

      今天突然靈機一動,該問題實質上是Hibernate Session機制管理的問題,於是搜到了一篇文章(見前一篇),着重講 Hibernate緩存機制 以及 Hibernate對象的狀態。看了以後,終於明白了緣由!

  

PS: 透過問題,看本質是最重要的。

         遇到問題,別急着去網上找;最好先理理思路,對問題進行較精確的歸類,然後再去查找,“有的放矢”效率會更高。

發佈了8 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章