hibernate之fetch

來源:互聯網
上載者:User

標籤:hibernate   orm   fetch   

    處理關聯關係是ORM中一常見操作,特別是在查詢的時候,經常要在查詢某個實體的時候要把它實體關聯屬性也查詢出來,例如查詢使用者時級聯查詢角色資訊,還有可能角色及聯查詢許可權資訊。在hibernate中實現這個目的有很多總方式:
1.配置OpenSessionInViewFilter,讓Session在View層中儲存開啟狀態,可以隨時使用,這看起來是個一勞永逸的辦法,但其也帶來了一些問題,  至於會有什麼樣的問題百度會給你答案。
2.在映射實體時把關聯屬性設定lazy="false",表示該關聯關係不進行懶載入,這樣該實體關聯屬性就會一起被查詢出來,這種方式有時候是可行的,但最大的問題就是不靈活,一但配置lazy="false",有時候不想該實體關聯屬性一起被查詢出來就無能為力了
3.在hql中提供了一個"fetch"關鍵字,其字面意義就是"抓取",利用它可以靈活地抓取我們想要查詢實體關聯屬性。例如:查詢使用者抓取角色:FROM User u LEFT JOIN FETCH u.roles rs WHERE...,如果角色還要抓取限制,則:FROM User u LEFT JOIN FETCH u.roles rs LEFT JOIN FETCH rs.privileges ps WHERE...

FETCH使用起來的確很靈活,但在最近的一次使用中卻碰見了一個問題,就是在得到的結果集中可能出現多條相同的記錄,這是我們所不想要的

舉個例子:

/** 論壇主題 **/public class Theme {/** 資料庫ID **/private  Integer  id;/** 標題 **/private  String  title;/** 主題內容 **/private  String  content;/** 回複 **/private Set<Reply> replies = new HashSet<Reply>();//getter...//setter...}

/** 主題回複 **/public class Reply {/**  資料庫id  **/private  Integer  id;/**  回複內容  **/private  String  content;/** 回複所屬主題 **/private Theme theme;//getter...//setter...}

   為了簡單起見,只是列出了樣本屬性,getter與setter方法也省略掉了。現在當我們查詢Theme的時候要抓取出Reply,這時hql語句為:FROM Theme t LEFT JOIN FETCH t.replies rs WHERE t.id=?,執行查詢後得到Query對象,這時你如果調用的是uniqueResult()方法你將得到正確的結果,但是當你調用的是list()方法,你會發現這個結果清單中很可能出現了多條重複的記錄,確切的說是該Theme有多少個Reply就會有多少條重複的記錄,這時你肯定會說調用uniqueResult()方法不就完了嗎?在這種本來就只有一條記錄的情況肯定是沒有問題的,但有時候我們想返回的就是多條記錄呢?比如,根據Theme的title屬性進行模糊比對(不考慮全文索引)的時候,這時hql語句為:FROM Theme t LEFT JOIN FETCH t.replies rs WHERE t.title like ?,我們要返回的就是一個List列表,這時只能調用Query.list()方法,這樣勢必會出現多條重複記錄。那麼如何解決呢?
1.加上DISTINCT關鍵字,hql變為:FROM DISTINCT Theme t LEFT JOIN FETCH t.replies rs WHERE t.title like ?,這樣一般情況下  能返回確定的結果,但有時候也不行。例如,在Oracle中當有欄位為clob,blob類型時就行不通過了,因為資料根本不知道對於clob,blob類型  的資料到底是不是相等,其它資料庫就沒有試過了,我估計也不行。所以DISTINCT關鍵字也不是萬能的。
2.在返回含有相同記錄的List中,手工進行排除掉相同的記錄,但這會增加額外的工作量,大家肯定也不願幹。
3.在調用list()方法之前,調用query.setFirstIndex(0).setMaxResult(Integer.MAX_VALUE);這樣一個分頁語句肯定是擷取出了全部的記錄  這樣雖然能擷取出正確的結果,但你會發現和沒有設定分頁執行的SQL語句是一樣的,這就說明在這種情況下hibernate是先擷取出了全部符合  條件的記錄然後再進行分頁的。當你不需要分頁的情況下執行是沒有問題的,如果你又想分頁又想級聯抓取就會擷取出不必要的記錄,因為  它是在記憶體中分頁的。而且這樣hibernate還會報一個警告:WARNING: firstResult/maxResults specified with collection fetch; applying in memory!  大致意思說的就是在記憶體中進行分頁,這樣肯定有效能方面的問題,這個問題可以參看:點擊開啟連結
 
   在相比之下,個人覺得還是第3種解決方案是最合適的(如果還有更好的解決方案請不吝賜教),因為只要不進行分頁都是可以滿足要求的,如果要進行分頁只能不進行級聯抓取了,要擷取實體關聯屬性另外寫查詢語句。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.