a different object with the same identifier value was already associated with the session 深入分析 – JAVA編程語言程序開發技術文章

一、先貼上網絡上摘的文章

1、a different object with the same identifier value was already associated with the session。
  錯誤原因:在hibernate中同一個session裡面有瞭兩個相同標識但是是不同實體。
  解決方法一:session.clean()
  PS:如果在clean操作後面又進行瞭saveOrUpdate(object)等改變數據狀態的操作,有可能會報出"Found two representations of same collection"異常。
  解決方法二:session.refresh(object)
  PS:當object不是數據庫中已有數據的對象的時候,不能使用session.refresh(object)因為該方法是從hibernate的session中去重新取object,如果session中沒有這個對象,則會報錯所以當你使用saveOrUpdate(object)之前還需要判斷一下。
  解決方法三:session.merge(object)
  PS:Hibernate裡面自帶的方法,推薦使用。
二、 我的分析 

  背景知識

DocType 裡面有一個WebSite對象屬性

  錯誤代碼

[java] /**
  * 刪除單條記錄
  * 
  * @param id 用於刪除的記錄的id
  * @return 成功刪除的記錄數
  */ 
 public void delete(Website website) throws Exception { 
     DocType docType = getDocTypeBS().getDocTypeByCode(ROOT, website.getId()); 
     if (docType != null) { 
         Set<DocType> docTypeSet = docType.getChildren(); 
         if (docTypeSet != null && docTypeSet.size() > 0) { 
             throw new Exception("此站點下有子欄目,不能刪除!"); 
         } else { 
             getDocTypeBS().delete(docType); 
             getDao().delete(website);  
         } 
     } 
 } 
   /**
     * 刪除單條記錄
     *
     * @param id 用於刪除的記錄的id
     * @return 成功刪除的記錄數
     */
    public void delete(Website website) throws Exception {
        DocType docType = getDocTypeBS().getDocTypeByCode(ROOT, website.getId());
        if (docType != null) {
            Set<DocType> docTypeSet = docType.getChildren();
            if (docTypeSet != null && docTypeSet.size() > 0) {
                throw new Exception("此站點下有子欄目,不能刪除!");
            } else {
                getDocTypeBS().delete(docType);
                getDao().delete(website);
            }
        }
    }

 

  修正代碼

[java] /**
    * 刪除單條記錄
    * 
    * @param id 用於刪除的記錄的id
    * @return 成功刪除的記錄數
    */ 
   public void delete(Website website) throws Exception { 
       DocType docType = getDocTypeBS().getDocTypeByCode(ROOT, website.getId()); 
       if (docType != null) { 
           Set<DocType> docTypeSet = docType.getChildren(); 
           if (docTypeSet != null && docTypeSet.size() > 0) { 
               throw new Exception("此站點下有子欄目,不能刪除!"); 
           } else { 
               //此處要註意,刪除時不能傳入參數的website對象,因為上面查出來的docType裡面級聯瞭此site對象,再傳入參數時會在session緩存中會出現兩個主鍵相同的實體www.aiwalls.com  
               getDao().delete(docType.getSite());  
               getDocTypeBS().delete(docType); 
           } 
       } 
   } 
 /**
     * 刪除單條記錄
     *
     * @param id 用於刪除的記錄的id
     * @return 成功刪除的記錄數
     */
    public void delete(Website website) throws Exception {
        DocType docType = getDocTypeBS().getDocTypeByCode(ROOT, website.getId());
        if (docType != null) {
            Set<DocType> docTypeSet = docType.getChildren();
            if (docTypeSet != null && docTypeSet.size() > 0) {
                throw new Exception("此站點下有子欄目,不能刪除!");
            } else {
                //此處要註意,刪除時不能傳入參數的website對象,因為上面查出來的docType裡面級聯瞭此site對象,再傳入參數時會在session緩存中會出現兩個主鍵相同的實體
                getDao().delete(docType.getSite());
                getDocTypeBS().delete(docType);
            }
        }
    }

我的分析 

這是由於查詢DocType的時候級聯查出瞭Website,導致Session中已經有瞭此Website實例瞭,再把遊離態的webSite對象傳入就會導致二個ID相同的對象,Hibernate會報錯的.

 

摘自 張仁陽專欄

發佈留言