Session.load/get方法均可以根據指定的實體類和id從資料庫讀取記錄,并傳回與之對應的實體對象。
其差別在于:
如果未能發現符合條件的記錄,get方法傳回null,而load方法會抛出一個ObjectNotFoundException。
Load方法可傳回實體的代理類執行個體,而get方法永遠直接傳回實體類。
load方法可以充分利用内部緩存和二級緩存中的現有資料,而get方法則僅僅在内部緩存中進行資料查找,如沒有發現對應資料,将越過二級緩存,直接調用SQL完成資料讀取。
Session在加載實體對象時,将經過的過程:
首先,Hibernate中維持了兩級緩存。第一級緩存由Session執行個體維護,其中保持了Session目前所有關聯實體的資料,也稱為内部緩存。而第二級緩存則存在于SessionFactory層次,由目前所有由本SessionFactory構造的Session執行個體共享。出于性能考慮,避免無謂的資料庫通路,Session在調用資料庫查詢功能之前,會先在緩存中進行查詢。首先在第一級緩存中,通過實體類型和id進行查找,如果第一級緩存查找命中,且資料狀态合法,則直接傳回。
之後,Session會在目前“NonExists(把無效的條件寫成一個黑名單,既然無效,那麼也沒必要再查下去)”記錄中進行查找,如果“NonExists”記錄中存在同樣的查詢條件,則傳回null。“NonExists”記錄了目前Session執行個體在之前所有查詢操作中,未能查詢到有效資料的查詢條件(相當于一個查詢黑名單清單)。如此一來,如果Session中一個無效的查詢條件重複出現,即可迅速作出判斷,進而獲得最佳的性能表現。
對于load方法而言,如果内部緩存中未發現有效資料,則查詢第二級緩存,如果第二級緩存命中,則傳回。
如在緩存中未發現有效資料,則發起資料庫查詢操作(Select SQL),如經過查詢未發現對應記錄,則将此次查詢的資訊在“NonExists”中加以記錄,并傳回null。
根據映射配置和Select SQL得到的ResultSet,建立對應的資料對象。
将其資料對象納入目前Session實體管理容器(一級緩存)。
執行Interceptor.onLoad方法(如果有對應的Interceptor)。
将資料對象納入二級緩存。
如果資料對象實作了LifeCycle接口,則調用資料對象的onLoad方法。
傳回資料對象。
/** *//**
* 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
轉載:
load和get一共是2個差別 先講第一個 延遲加載
load是true而get是false
意 思就是 load采用的是延遲加載的方式 而get不是,hibernate思想是 既然這個方法支援延遲加載 他就認為這個對象一定在資料庫存在,在你 聲明 TFaq tfag2=(TFaq)sess.load(TFaq.class, 300); 這句時候,hibernate就幹了一件事
1.查詢session緩存
2.緩存中沒有這個對象 就建立個代理
因為延遲加載需要代理來執行 是以就建立了個代理
ok 到此為止 這句話就幹了個這個 并沒有去資料庫互動查詢
當你使用這個對象 比如tfag2.getTfRtitle()或get方法時候
這個時候 hibernate就去查詢二級緩存和資料庫,資料庫沒有這條資料 就抛出異常
整個load方法調用結束 load沒什麼神奇 這就是他幹過所有的事情
load方法講完了 我在講一下get方法工作原理
因為hibernate規定get方法不能使用延遲加載 是以和load還是不一樣的
TFaq tfag2=(TFaq)sess.get(TFaq.class, 300);
在建立這條語句時候 我們看看hibernate幹了哪些事
1.get方法首先查詢session緩存 (session緩存就是hibernate的一級緩存 這個概念大家應該清楚吧 )
2.get方法如果在session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象延遲加載過,那麼傳回的還是原先的代理對象,而不是實體類對象。
3.如果該代理對象還沒有加載實體資料(就是id以外的其他屬性資料),那麼它會查詢二級緩存或者資料庫來加載資料,但是傳回的還是代理對象,隻不過已經加載了實體資料。
(這個代理實際就是空的對象 并沒有去資料庫查詢得到的 我們叫代理對象,如果 去資料庫查詢了 傳回到了這個對象 我們叫實體對象 就是這個對象真實存在)
我在總結性一句話這2者差別
get方法首先查詢session緩存,沒有的話查詢二級緩存,最後查詢資料庫;反而load方法建立時首先查詢session緩存,沒有就建立代理,實際使用資料時才查詢二級緩存和資料庫
----我測試過:
在使用session.get方法後如果把session關閉的話,也會出現懶加載異常。
那麼隻有在manytoone标簽裡配置 lazy="false"時異常才會解決。
也就是說上面轉載的第3條不是那麼正确:傳回該代理對象不錯,但是如果該對象沒有加載實體資料,那麼也會在用到時才會加載,即不會立即查詢資料庫或者二級緩存,那麼你現在把session關閉,這個對行啊沒有加載實體資料----才會出現懶加載異常。