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才真正執行數據庫查詢操作。
注意:
01.StudentEh s=(StudentEh)session.load(StudentEh.class,10);
02.
03.System.out.println(s.getId());
這兩條語句同樣不會產生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已關閉的錯誤。