hibernate N+1問題

Hibernate N+1 問題及解決辦法sql

問題出現的緣由:數據庫

Hibernate 中常會用到 set , bag 等集合表示 1 對多的關係,在獲取實體的時候就能根據關係將關聯的對象或者對象集取出,還能夠設定 cacade 進行關聯更新和刪除。這不得不說 hibernate 的 orm 作得很好,很貼近 oo的使用習慣了。緩存

可是對數據庫訪問仍是必須考慮性能問題的,在設定了 1 對多這種關係以後, 查詢就會出現傳說中的 n+1 問題。性能

一對多: 在一方,查找獲得了 n 個對象,那麼又須要將 n 個對象關聯的集合取出,因而原本的一條 sql 查詢變成了 n+1 條;fetch

多對一: 在多方,查詢獲得了 m 個對象,那麼也會將 m 個對象對應的 1 方的對象取出, 也變成了 m+1 ;spa

解決問題的方法:hibernate

      一、 使用 fetch 抓取, Hibernate 抓取策略分爲單端代理和集合代理的抓取策略。代理

Hibernate 抓取策略 ( 單端代理的抓取策略 ) orm

   保持默認也就是以下 :對象

    <many-to-one name="clazz" cascade="save-update" fetch="select" />

    fetch="select" 就是另外發送一條 select 語句抓取當前對象關聯實體或者集合設置 fetch="join"

     <many-to-one name="clazz" cascade="save-update" fetch="join"/>

Hibernate 會經過 select 語句使用外鏈接來加載器關聯實體活集合此時 lazy 會失效

       Hibernate 抓取策略 ( 集合代理的抓取策略 ) 

            保持默認( fetch="select" )也就是以下 :

        <set name="students" inverse="true">

                 <key column="clazz"/>

                 <one-to-many class="com.june.hibernate.Student"/>

             </set>

             1)fetch="select" 會另外發出一條語句查詢集合

             2) 設置 fetch="join" 採用外鏈接集合的 lazy 失效

             3) 這隻 fetch="subselect" 另外發出一條 select 語句抓取前面查詢到的全部的實體對象的關聯集合 fetch只對 HQL 查詢產生影響其餘的則不會

       二、 使用 map 直接搜索須要的列

如:產品 product 和產品分類 product_category 兩張表,多對一關係。查詢產品列表時

select new Map(p.id as id, p.name as name, p.category.name as categoryName) from Product p

對數據庫訪問仍是必須考慮性能問題的, 在設定了1 對多這種關係以後, 查詢就會出現傳說中的n +1 問題。 
1 )1 對多,在1 方,查找獲得了n 個對象, 那麼又須要將n 個對象關聯的集合取出,因而原本的一條sql查詢變成了n +1 條 
2)多對1 ,在多方,查詢獲得了m個對象,那麼也會將m個對象對應的1 方的對象取出, 也變成了m+1

怎麼解決n +1 問題? 
1 )lazy=true, hibernate3開始已經默認是lazy=true了;lazy=true時不會馬上查詢關聯對象,只有當須要關聯對象(訪問其屬性,非id字段)時纔會發生查詢動做。 

2)二級緩存, 在對象更新,刪除,添加相對於查詢要少得多時, 二級緩存的應用將不怕n +1 問題,由於即便第一次查詢很慢,以後直接緩存命中也是很快的。 
不一樣解決方法,不一樣的思路,第二條卻恰好又利用了n +1 。

3) 固然你也能夠設定fetch=join(annotation : @ManyToOne() @Fetch(FetchMode.JOIN))

相關文章
相關標籤/搜索