Session.load/get方法均可以根據指定的實體類和id從數據庫讀取記錄,並返回與之對應的實體對象。其區別在於:
1. 對於get方法,hibernate會確認一下該id對應的數據是否存在,首先在session緩存中查找,然后在二級緩存中查找,還沒有就查詢數據庫,數據庫中沒有就返回null。
2. load方法加載實體對象的時候,根據映射文件上類級別的lazy屬性的配置(默認為true),分情況討論:
(1)若為true,則首先在Session緩存中查找,看看該id對應的對象 是否 存在,不存在則使用延遲加載,返回實體的代理類對象(該代理類為實體類的子類,由CGLIB動態生成)。等到具體使用該對象(除獲取OID以外)的時候, 再查詢二級緩存和數據庫,若仍沒發現符合條件的記錄,則會拋出一個ObjectNotFoundException。
(2)若為false,就跟get方法查找順序一樣,只是最終若沒發現符合條件的記錄,則會拋出一個ObjectNotFoundException。
這里get和load有兩個重要區別:
如果未能發現符合條件的記錄,get方法返回null,而load方法會拋出一個ObjectNotFoundException。
load方法可返回沒有 加載實體數據的代理類實例,而get方法永遠返回有實體數據的對象。(對於load和get方法返回類型:好多書中都說:“get方法永遠只返回實體 類”,實際上並不正確,get方法如果在session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被 其他關聯對象延遲加載過,那么返回的還是原先的代理對象,而不是實體類對象,如果該代理對象還沒有加載實體數據(就是id以外的其他屬性數據),那么它會 查詢二級緩存或者數據庫來加載數據,但是返回的還是代理對象,只不過已經加載了實體數據。)
- Users user = (Users)session.load(Users.class, userId);
這句代碼不會去執行數據庫查詢,只有用到user時才會去執行數據庫查詢。
而:
- Users user = (Users)session.get(Users.class, userId);
則立即去執行數據庫查詢。 所以Users user = (Users)session.load(Users.class, userId);不會執行任何sql。
注意:
- Users user = (Users)session.load(Users.class, userId);
- System.out.println(user.getId());
上面這2句代碼,不會去執行數據庫操作。因為load后會在hibernate的一級緩存里存放一個map對象,該map的key就是userId的值,但是當你getId()時,它會去一級緩存里拿map的key值,而不去執行數據庫查詢。所以不會報任何錯。不會執行任何數據庫操作。
並且注意:這兩個方法的第二個參數id,它必須是實現了Java.io.Serializable接口,也就是可序列化的。
/** *//**
* load()方法的執行順序如下:
* a):首先通過id在session緩存中查找對象,如果存在此id的對象,直接將其返回
* b):在二級緩存中查找,找到后將 其返回。
* c):如果在session緩存和二級緩存中都找不到此對象,則從數據庫中加載有此ID的對象
* 因此load()方法並不總是導致SQL語句,只有緩存中無此數據時,才向數據庫發送SQL!
*/
/** *//**
* 與get()的區別:
* 1:在立即加載對象(當hibernate在從數據庫中取得數據組裝好一個對象后
* 會立即再從數據庫取得數據此對象所關聯的對象)時,如果對象存在,
* load()和get()方法沒有區別,都可以取得已初始化的對象;但如果當對
* 象不存在且是立即加載時,使用get()方法則返回null,而使用load()則
* 拋出一個異常。因此使用load()方法時,要確認查詢的主鍵ID一定是存在
* 的,從這一點講它沒有get方便!
* 2:在延遲加載對象(Hibernate從數據庫中取得數據組裝好一個對象后,
* 不會立即再從數據庫取得數據組裝此對象所關聯的對象,而是等到需要時,
* 都會從數據庫取得數據組裝此對象關聯的對象)時,get()方法仍然使用
* 立即加載的方式發送SQL語句,並得到已初始化的對象,而load()方法則
* 根本不發送SQL語句,它返回一個代理對象,直到這個對象被訪問時才被
* 初始化。
*/
get()----不支持LAZY
load()----支持LAZY