Hibernate中Session.load/get方法均可以根據指定的實體類和id從資料庫讀取記錄,並返回與之對應的實體物件。其區別在於:
1.get()方法直接返回實體類,load()方法可以返回實體的代理類執行個體。
2.hibernate load是採用延遲機制(當lazy屬性為true時) 而get不採用延遲機制(get語句馬上讀庫)
3.找不到合格資料 get方法將返回null
load將會報出ObjectNotFoundExcepion
4.get支援多態查詢,load只有在lazy=false的情況下才支援多態查詢
所謂多態查詢,就是可以明確區分載入的是什麼類型的對象,load採用代理機制無法支援
消極式載入:Hibernate盡量延遲向資料庫發送sql,它自己有一個緩衝區,先把sql放在裡面,最後一起發送,減少網路開銷和資料庫開銷。
load方法原理:
當對象.hbm.xml設定檔元素的lazy屬性設定為true時,調用load()方法時則返回持久對象的代理類執行個體,此時的代理類執行個體是由運行時動態產生的類,該代理類執行個體包括原目標對象的所有屬性和方法,該代理類執行個體的屬性除了ID不為null外,所在屬性為null值,查看日誌並沒有Hibernate SQL輸出,說明沒有執行查詢操作,當代理類執行個體通過getXXX()方法擷取屬性值時,Hiberante才真正執行資料庫查詢操作。
注意:
StudentEh s=(StudentEh)session.load(StudentEh.class,10);</p><p>System.out.println(s.getId());<br />
這兩條語句同樣不會產生sql語句,因為session.load後會在hibernate的一級緩衝裡存放一個map對象,該map的key就是id的值,但是當你getId()時,它是從一級緩衝裡取map的key值,而不去執行資料庫查詢。
當對象.hbm.xml設定檔元素的lazy屬性設定為false時,調用load()方法則是立即執行資料庫並直接返回實體類,並不返回代理類。而調用get()方法時不管lazy為何值,都直接返回實體類。
get方法原理:
get方法,hibernate會確認一下該id對應的資料是否存在,首先在session緩衝中尋找,然後在二級緩衝中尋找,還沒有就查資料庫,資料庫中沒有就返回null。
get方法如果在session緩衝中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象消極式載入過,那麼返回的還是原先的代理對象,而不是實體類對象,如果該代理對象還沒有載入實體資料(就是id以外的其他屬性資料),那麼它會查詢二級緩衝或者資料庫來載入資料,但是返回的還是代理對象,只不過已經載入了實體資料。
總結描述:
如果使用load方法,hibernate認為該id對應的對象(資料庫記錄)在資料庫中是一定存在的,所以它可以放心的使用代理來消極式載入該對象。在用到對象中的其他屬性資料時才查詢資料庫,但是萬一資料庫中不存在該記錄,那沒辦法,只能拋異常,所說的load方法拋異常是指在使用該對象的資料時,資料庫中不存在該資料時拋異常,而不是在建立這個對象時。由於session中的緩衝對於hibernate來說是個相當廉價的資源,所以在load時會先查一下session緩衝看看該id對應的對象是否存在,不存在則建立代理。所以如果你知道該id在資料庫中一定有對應記錄存在就可以使用load方法來實現消極式載入。
而對於get方法,hibernate一定要擷取到真實的資料,否則返回null。
自己在開發過程中遇到的問題:
我們用MyEclipse hibernate工具通過資料庫產生的DAO類,它的findById方法是用的session.get()方法,這是即時獲得pojo對象,如果是load方法,在執行完load後如果關閉了session,那在接下來用到這個pojo對象時就會報session已關閉的錯誤。