HIBERNATE的N 1查詢問題

2021-06-20 05:39:11 字數 3265 閱讀 6612

在session的快取中存放的是相互關聯的物件圖。預設情況下,當hibernate從資料庫中載入customer物件時,會同時載入所有關聯的order物件。以customer和order類為例,假定orders表的customer_id外來鍵允許為null,圖1列出了customers表和orders表中的記錄。

以下session的find()方法用於到資料庫中檢索所有的customer物件:

list customerlists=session.find("from customer as c");

執行以上find()方法時,hibernate將先查詢customers表中所有的記錄,然後根據每條記錄的id,到orders表中查詢有參照關係的記錄,hibernate將依次執行以下select語句:

select * from customers;

select * from orders where customer_id=1;

select * from orders where customer_id=2;

select * from orders where customer_id=3;

select * from orders where customer_id=4;

通過以上5條select語句,hibernate最後載入了4個customer物件和5個order物件,在記憶體中形成了一幅關聯的物件圖,參見圖2。

hibernate在檢索與customer關聯的order物件時,使用了預設的立即檢索策略。這種檢索策略存在兩大不足:

(1) select語句的數目太多,需要頻繁的訪問資料庫,會影響檢索效能。如果需要查詢n個customer物件,那麼必須執行n+1次select查詢語句。這就是經典的

n+1次

select

查詢問題。這種檢索策略沒有利用sql的連線查詢功能,例如以上5條select語句完全可以通過以下1條select語句來完成:

select * from customers left outer join orders

on customers.id=orders.customer_id

以上select語句使用了sql的左外連線查詢功能,能夠在一條select語句中查詢出customers表的所有記錄,以及匹配的orders表的記錄。

(2)在應用邏輯只需要訪問customer物件,而不需要訪問order物件的場合,載入order物件完全是多餘的操作,這些多餘的order物件白白浪費了許多記憶體空間。

為了解決以上問題,hibernate提供了兩種檢索策略:延遲檢索策略和迫切左外連線檢索策略

1、延遲檢索策略能避免多餘載入應用程式不需要訪問的關聯物件,

hibernate3

開始已經預設是

lazy=true

了;lazy=true

時不會立刻查詢關聯物件,只有當需要關聯物件(訪問其屬性

)時才會發生查詢動作。

2、迫切左外連線檢索策略則充分利用了sql的外連線查詢功能,能夠減少select語句的數目。

可以在對映檔案中定義連線抓取方式。

或者使用hql的left outer join.

或者在條件查詢中使用setfetchmode(fetchmode.join)

customer ctm = (customer)session.createcriteria(customer.class)

.setfetchmode(「order」.join)

.add(restrictions.ideq(customer_id));

hibernate fetch 和lazy

經過測試發現hibernate annotation中@manytoone,@onetomany,@onetoone中lazy的預設值是不同的

@onetomany   預設fetch=fetchtype.lazy

@manytoone  @onetoone  預設fetch=fetchtype.enger

在設定@manytoone的時候我們一般都會設定lazy=true

一般不會在@manytoone,@onetoone考慮這個問題

但實際hibernate進行load是時候是把一端也load出來的

fetch 和 lazy 主要是用來級聯查詢的

而 cascade 和 inverse 主要是用來級聯插入和修改的

fetch引數指定了關聯物件抓取的方式是select查詢還是join查詢,

select方式時先查詢返回要查詢的主體物件(列表),再根據關聯外來鍵 id,每乙個物件發乙個select查詢,獲取關聯的物件,形成n+1次查詢;

而join方式,主體物件和關聯物件用一句外來鍵關聯的sql同時查詢出來,不會形成多次查詢。

如果你的關聯物件是延遲載入的,它當然不會去查詢關聯物件。

另外,在hql查詢中配置檔案中設定的join方式是不起作用的(而在所有其他查詢方式如get、criteria或再關聯獲取等等都是有效的),會使用 select方式,除非你在hql中指定join fetch某個關聯物件。

預設配置

annotations

lazy

fetch

@[one|many]toone](fetch=fetchtype.lazy)

@lazytoone(proxy)

@fetch(select)

@[one|many]toone](fetch=fetchtype.eager)

@lazytoone(false)

@fetch(join)

@manyto[one|many](fetch=fetchtype.lazy)

@lazycollection(true)

@fetch(select)

@manyto[one|many](fetch=fetchtype.eager)

@lazycollection(false)

@fetch(join)

即fetch=fetchtype.lazy則@fetch(select)。fetch=fetchtype.eager則@fetch(join)

fetch

a)        鐵律:雙向不要兩邊設定eager(會有多餘的查詢語句發出)

b)        對多方設定fetch的時候要謹慎,結合具體應用,一般用lazy不用eager,特殊情況(多方數量不多的可以考慮,提高效率的時候可以考慮)

fetch策略用於定義 get/load乙個物件時,如何獲取非lazy的物件/集合。 這些引數在query中無效

hibernate的n 1查詢問題

在 session 的快取中存放的是相互關聯的物件圖。預設情況下,當 hibernate 從資料庫中載入 customer 物件時,會同時載入所有關聯的 order 物件。以 customer 和order 類為例,假定 orders 表的customer id 外來鍵允許為 null,圖1 列出了...

Hibernate解決n 1問題

觀點 對於n 1問題的理解。一般而言說n 1意思是,無論在一對多還是多對一當查詢出n條資料之後,每條資料會關聯的查詢1次他的關聯物件,這就叫做n 1。但是我的理解是,本來所有資訊可以一次性查詢出來,也就是簡單的連表查詢,但是hibernate會首先查詢1次得到當前物件,然後當前物件裡面的n個關聯物件...

hibernate中的n 1問題

前提 hibernate預設表與表的關聯方法是fetch select 不是fetch join 這都是為了懶載入而準備的。1 一對多 在1的這方,通過1條sql查詢得到了1個物件,由於關聯的存在 那麼又需要將這個物件關聯的集合取出,所以合集數量是n還要發出n條sql,於是本來的1條sql查詢變成了...