Session中l(wèi)oad/get方法的詳細(xì)區(qū)別

Session.load/get方法均可以根據(jù)指定的實(shí)體類(lèi)和id從數(shù)據(jù)庫(kù)讀取記錄,并返回與之對(duì)應(yīng)的實(shí)體對(duì)象。

其區(qū)別在于:

如果未能發(fā)現(xiàn)符合條件的記錄,get方法返回null,而load方法會(huì)拋出一個(gè)ObjectNotFoundException。

Load方法可返回實(shí)體的代理類(lèi)實(shí)例,而get方法永遠(yuǎn)直接返回實(shí)體類(lèi)。

load方法可以充分利用內(nèi)部緩存和二級(jí)緩存中的現(xiàn)有數(shù)據(jù),而get方法則僅僅在內(nèi)部緩存中進(jìn)行數(shù)據(jù)查找,如沒(méi)有發(fā)現(xiàn)對(duì)應(yīng)數(shù)據(jù),將越過(guò)二級(jí)緩存,直接調(diào)用SQL完成數(shù)據(jù)讀取。

Session在加載實(shí)體對(duì)象時(shí),將經(jīng)過(guò)的過(guò)程:

首先,Hibernate中維持了兩級(jí)緩存。第一級(jí)緩存由Session實(shí)例維護(hù),其中保持了Session當(dāng)前所有關(guān)聯(lián)實(shí)體的數(shù)據(jù),也稱(chēng)為內(nèi)部緩存。而第二級(jí)緩存則存在于SessionFactory層次,由當(dāng)前所有由本SessionFactory構(gòu)造的Session實(shí)例共享。出于性能考慮,避免無(wú)謂的數(shù)據(jù)庫(kù)訪(fǎng)問(wèn),Session在調(diào)用數(shù)據(jù)庫(kù)查詢(xún)功能之前,會(huì)先在緩存中進(jìn)行查詢(xún)。首先在第一級(jí)緩存中,通過(guò)實(shí)體類(lèi)型和id進(jìn)行查找,如果第一級(jí)緩存查找命中,且數(shù)據(jù)狀態(tài)合法,則直接返回。

之后,Session會(huì)在當(dāng)前“NonExists(把無(wú)效的條件寫(xiě)成一個(gè)黑名單,既然無(wú)效,那么也沒(méi)必要再查下去)”記錄中進(jìn)行查找,如果“NonExists”記錄中存在同樣的查詢(xún)條件,則返回null。“NonExists”記錄了當(dāng)前Session實(shí)例在之前所有查詢(xún)操作中,未能查詢(xún)到有效數(shù)據(jù)的查詢(xún)條件(相當(dāng)于一個(gè)查詢(xún)黑名單列表)。如此一來(lái),如果Session中一個(gè)無(wú)效的查詢(xún)條件重復(fù)出現(xiàn),即可迅速作出判斷,從而獲得最佳的性能表現(xiàn)。

對(duì)于load方法而言,如果內(nèi)部緩存中未發(fā)現(xiàn)有效數(shù)據(jù),則查詢(xún)第二級(jí)緩存,如果第二級(jí)緩存命中,則返回。

如在緩存中未發(fā)現(xiàn)有效數(shù)據(jù),則發(fā)起數(shù)據(jù)庫(kù)查詢(xún)操作(Select SQL),如經(jīng)過(guò)查詢(xún)未發(fā)現(xiàn)對(duì)應(yīng)記錄,則將此次查詢(xún)的信息在“NonExists”中加以記錄,并返回null。

根據(jù)映射配置和Select SQL得到的ResultSet,創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)對(duì)象。

將其數(shù)據(jù)對(duì)象納入當(dāng)前Session實(shí)體管理容器(一級(jí)緩存)。

執(zhí)行Interceptor.onLoad方法(如果有對(duì)應(yīng)的Interceptor)。

將數(shù)據(jù)對(duì)象納入二級(jí)緩存。

如果數(shù)據(jù)對(duì)象實(shí)現(xiàn)了LifeCycle接口,則調(diào)用數(shù)據(jù)對(duì)象的onLoad方法。

返回?cái)?shù)據(jù)對(duì)象。

/** *//**

* load()方法的執(zhí)行順序如下:

* a):首先通過(guò)id在session緩存中查找對(duì)象,如果存在此id的對(duì)象,直接將其返回

* b):在二級(jí)緩存中查找,找到后將 其返回。

* c):如果在session緩存和二級(jí)緩存中都找不到此對(duì)象,則從數(shù)據(jù)庫(kù)中加載有此ID的對(duì)象

* 因此load()方法并不總是導(dǎo)致SQL語(yǔ)句,只有緩存中無(wú)此數(shù)據(jù)時(shí),才向數(shù)據(jù)庫(kù)發(fā)送SQL!

*/

/** *//**

* 與get()的區(qū)別:

* 1:在立即加載對(duì)象(當(dāng)hibernate在從數(shù)據(jù)庫(kù)中取得數(shù)據(jù)組裝好一個(gè)對(duì)象后

* 會(huì)立即再?gòu)臄?shù)據(jù)庫(kù)取得數(shù)據(jù)此對(duì)象所關(guān)聯(lián)的對(duì)象)時(shí),如果對(duì)象存在,

* load()和get()方法沒(méi)有區(qū)別,都可以取得已初始化的對(duì)象;但如果當(dāng)對(duì)

* 象不存在且是立即加載時(shí),使用get()方法則返回null,而使用load()則

* 拋出一個(gè)異常。因此使用load()方法時(shí),要確認(rèn)查詢(xún)的主鍵ID一定是存在

* 的,從這一點(diǎn)講它沒(méi)有g(shù)et方便!

* 2:在延遲加載對(duì)象(Hibernate從數(shù)據(jù)庫(kù)中取得數(shù)據(jù)組裝好一個(gè)對(duì)象后,

* 不會(huì)立即再?gòu)臄?shù)據(jù)庫(kù)取得數(shù)據(jù)組裝此對(duì)象所關(guān)聯(lián)的對(duì)象,而是等到需要時(shí),

* 都會(huì)從數(shù)據(jù)庫(kù)取得數(shù)據(jù)組裝此對(duì)象關(guān)聯(lián)的對(duì)象)時(shí),get()方法仍然使用

* 立即加載的方式發(fā)送SQL語(yǔ)句,并得到已初始化的對(duì)象,而load()方法則

* 根本不發(fā)送SQL語(yǔ)句,它返回一個(gè)代理對(duì)象,直到這個(gè)對(duì)象被訪(fǎng)問(wèn)時(shí)才被

* 初始化。

*/

get()----不支持LAZY

load()----支持LAZY

load和get一共是2個(gè)區(qū)別 先講第一個(gè) 延遲加載

load是true而get是false

意 思就是 load采用的是延遲加載的方式 而get不是,hibernate思想是 既然這個(gè)方法支持延遲加載 他就認(rèn)為這個(gè)對(duì)象一定在數(shù)據(jù)庫(kù)存在,在你 聲明 TFaq tfag2=(TFaq)sess.load(TFaq.class, 300); 這句時(shí)候,hibernate就干了一件事

1.查詢(xún)session緩存

2.緩存中沒(méi)有這個(gè)對(duì)象 就創(chuàng)建個(gè)代理

因?yàn)檠舆t加載需要代理來(lái)執(zhí)行 所以就創(chuàng)建了個(gè)代理

ok 到此為止 這句話(huà)就干了個(gè)這個(gè) 并沒(méi)有去數(shù)據(jù)庫(kù)交互查詢(xún)

當(dāng)你使用這個(gè)對(duì)象 比如tfag2.getTfRtitle()或get方法時(shí)候

這個(gè)時(shí)候 hibernate就去查詢(xún)二級(jí)緩存和數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)沒(méi)有這條數(shù)據(jù) 就拋出異常

整個(gè)load方法調(diào)用結(jié)束 load沒(méi)什么神奇 這就是他干過(guò)所有的事情

load方法講完了 我在講一下get方法工作原理

因?yàn)閔ibernate規(guī)定get方法不能使用延遲加載 所以和load還是不一樣的

TFaq tfag2=(TFaq)sess.get(TFaq.class, 300);

在創(chuàng)建這條語(yǔ)句時(shí)候 我們看看hibernate干了哪些事

1.get方法首先查詢(xún)session緩存 (session緩存就是hibernate的一級(jí)緩存 這個(gè)概念大家應(yīng)該清楚吧 )

2.get方法如果在session緩存中找到了該id對(duì)應(yīng)的對(duì)象,如果剛好該對(duì)象前面是被代理過(guò)的,如被load方法使用過(guò),或者被其他關(guān)聯(lián)對(duì)象延遲加載過(guò),那么返回的還是原先的代理對(duì)象,而不是實(shí)體類(lèi)對(duì)象。

3.如果該代理對(duì)象還沒(méi)有加載實(shí)體數(shù)據(jù)(就是id以外的其他屬性數(shù)據(jù)),那么它會(huì)查詢(xún)二級(jí)緩存或者數(shù)據(jù)庫(kù)來(lái)加載數(shù)據(jù),但是返回的還是代理對(duì)象,只不過(guò)已經(jīng)加載了實(shí)體數(shù)據(jù)。

(這個(gè)代理實(shí)際就是空的對(duì)象 并沒(méi)有去數(shù)據(jù)庫(kù)查詢(xún)得到的 我們叫代理對(duì)象,如果 去數(shù)據(jù)庫(kù)查詢(xún)了 返回到了這個(gè)對(duì)象 我們叫實(shí)體對(duì)象 就是這個(gè)對(duì)象真實(shí)存在)

我在總結(jié)性一句話(huà)這2者區(qū)別

get方法首先查詢(xún)session緩存,沒(méi)有的話(huà)查詢(xún)二級(jí)緩存,最后查詢(xún)數(shù)據(jù)庫(kù);反而load方法創(chuàng)建時(shí)首先查詢(xún)session緩存,沒(méi)有就創(chuàng)建代理,實(shí)際使用數(shù)據(jù)時(shí)才查詢(xún)二級(jí)緩存和數(shù)據(jù)庫(kù)

----我測(cè)試過(guò):

在使用session.get方法后如果把session關(guān)閉的話(huà),也會(huì)出現(xiàn)懶加載異常。

那么只有在manytoone標(biāo)簽里配置 lazy="false"時(shí)異常才會(huì)解決。

也就是說(shuō)上面轉(zhuǎn)載的第3條不是那么正確:返回該代理對(duì)象不錯(cuò),但是如果該對(duì)象沒(méi)有加載實(shí)體數(shù)據(jù),那么也會(huì)在用到時(shí)才會(huì)加載,即不會(huì)立即查詢(xún)數(shù)據(jù)庫(kù)或者二級(jí)緩存,那么你現(xiàn)在把session關(guān)閉,這個(gè)對(duì)行啊沒(méi)有加載實(shí)體數(shù)據(jù)----才會(huì)出現(xiàn)懶加載異常。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容