在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查詢變成了...