Hibernate懶加載解析java
在Hibernate框架中,當咱們要訪問的數據量過大時,明顯用緩存不太合適, 由於內存容量有限 ,爲了減小併發量,減小系統資源的消耗,這時Hibernate用懶加載機制來彌補這種缺陷,可是這只是彌補而不是用了懶加載整體性能就提升了。sql
咱們所說的懶加載也被稱爲延遲加載,它在查詢的時候不會馬上訪問數據庫,而是返回代理對象,當真正去使用對象的時候纔會訪問數據庫。數據庫
實現懶加載的前提: 緩存
1 實體類不能是final的session
2 能實現懶加載的對象都是被CGLIB(反射調用)改寫的代理對象,因此不能是final修飾的
3 需要asm,cglib兩個jar包
4 相應的lazy屬性爲true
5 相應的fetch屬性爲select
下面幾種能夠實現懶加載功能:併發
一、 經過Session.load()實現懶加載框架
load(Object, Serializable):根據id查詢 。查詢返回的是代理對象,不會馬上訪問數據庫,是懶加載的。當真正去使用對象的時候纔會訪問數據庫。性能
用load()的時候會發現不會打印出查詢語句,而使用get()的時候會打印出查詢語句。fetch
使用load()時若是在session關閉以後再查詢此對象,會報異常:could not initialize proxy - no Session。處理辦法:在session關閉以前初始化一下查詢出來的對象:Hibernate.initialize(user);hibernate
使用load()能夠提升效率,由於剛開始的時候並無查詢數據庫。但不多使用。
二、 one-to-one(元素)實現了懶加載。
在一對一的時候,查詢主對象時默認不是懶加載。即:查詢主對象的時候也會把從對象查詢出來。
須要把主對象配製成lazy="true" constrained="true" fetch="select"。此時查詢主對象的時候就不會查詢從對象,從而實現了懶加載。
一對一的時候,查詢從對象的是默認是懶加載。即:查詢從對象的時候不會把主對象查詢出來。而是查詢出來的是主對象的代理對象。
三、 many-to-one(元素)實現了懶加載。
多對一的時候,查詢主對象時默認是懶加載。即:查詢主對象的時候不會把從對象查詢出來。
多對一的時候,查詢從對象時默認是懶加載。即:查詢從對象的時候不會把主對象查詢出來。
hibernate3.0中lazy有三個值,true,false,proxy,默認的是lazy="proxy".具體設置成什麼要看你的需求,並非說哪一個設置就是最好的。在<many-to-one>與<one-to-one>標籤上:當爲true時,會有懶加載特性,當爲false時會產生N+1問題,好比一個學生對應一個班級,用一條SQL查出10個學生,當訪問學生的班級屬性時Hibernate會再產生10條SQL分別查出每一個學生對應的班級.
lazy= 何時捉取
fetch= 捉取方式:select=關聯查詢;join=鏈接表的方式查詢(效率高)
fetch=join時,lazy的設置將沒有意義.
四、 one-to-many(元素)懶加載:默認會懶加載,這是必須的,是重經常使用的。
一對多的時候,查詢主對象時默認是懶加載。即:查詢主對象的時候不會把從對象查詢出來。
一對多的時候,查詢從對象時默認是懶加載。即:查詢從對象的時候不會把主對象查詢出來。
須要配置主對象中的set集合lazy="false" 這樣就配置成是不懶加載了。或者配置抓取方式fetch="join"也能夠變成不懶加載。
實現懶加載的方案:
方法一:(沒有使用懶加載)
用 Hibernate.initialize(de.getEmps()) 提早加載一下.
方法二:
把與Session脫離的對象從新綁定
lock()方法是用來讓應用程序把一個未修改的對象從新關聯到新session的方法。
//直接從新關聯
session.lock(fritz,LockMode.NONE);
//進行版本檢查後關聯
session.lock(izi,LockMode.READ);
//使用SELECT... FOR UPDATE進行版本檢查後關聯
session.lock(pk,LockMode.UPGRADE);
方法三:
OpenSessionInView
參見 http://www.javaeye.com/topic/32001
fetch 和 lazy 配置用於數據的查詢
lazy 參數值常見有 false 和 true,Hibernate3映射文件中默認lazy = true ;
fetch 指定了關聯對象抓取的方式,參數值常見是select和join,默認是select,select方式先查詢主對象,再根據關聯外鍵,每個對象發一個select查詢,獲取關聯的對象,造成了n+1次查詢;而join方式,是leftouter join查詢,主對象和關聯對象用一句外鍵關聯的sql同時查詢出來,不會造成屢次查詢。
在映射文件中,不一樣的組合會使用不一樣的查詢:
一、lazy="true" fetch = "select" ,使用延遲策略,開始只查詢出主對象,關聯對象不會查詢,只有當用到的時候纔會發出sql語句去查詢 ;
二、lazy="false" fetch = "select" ,沒有用延遲策略,同時查詢出主對象和關聯對象,產生1+n條sql.
三、lazy="true"或lazy="false"fetch = "join",延遲都不會做用,由於採用的是外鏈接查詢,同時把主對象和關聯對象都查詢出來了.
另 外,在hql查詢中,配置文件中設置的join方式是不起做用的,而在其餘查詢方式如get、criteria等是有效的,使用 select方式;除非在hql中指定join fetch某個關聯對象。fetch策略用於get/load一個對象時,如何獲取非lazy的對象/集合。 這些參數在Query中無效