Session.load/get方法均可以根據(jù)指定的實(shí)體類和id從數(shù)據(jù)庫讀取記錄,并返回與之對(duì)應(yīng)的實(shí)體對(duì)象赎线。
其區(qū)別在于:
如果未能發(fā)現(xiàn)符合條件的記錄痛侍,get方法返回null,而load方法會(huì)拋出一個(gè)ObjectNotFoundException宪彩。
Load方法可返回實(shí)體的代理類實(shí)例休讳,而get方法永遠(yuǎn)直接返回實(shí)體類。
load方法可以充分利用內(nèi)部緩存和二級(jí)緩存中的現(xiàn)有數(shù)據(jù)尿孔,而get方法則僅僅在內(nèi)部緩存中進(jìn)行數(shù)據(jù)查找俊柔,如沒有發(fā)現(xiàn)對(duì)應(yīng)數(shù)據(jù),將越過二級(jí)緩存活合,直接調(diào)用SQL完成數(shù)據(jù)讀取雏婶。
Session在加載實(shí)體對(duì)象時(shí),將經(jīng)過的過程:
首先白指,Hibernate中維持了兩級(jí)緩存留晚。第一級(jí)緩存由Session實(shí)例維護(hù),其中保持了Session當(dāng)前所有關(guān)聯(lián)實(shí)體的數(shù)據(jù)告嘲,也稱為內(nèi)部緩存倔丈。而第二級(jí)緩存則存在于SessionFactory層次,由當(dāng)前所有由本SessionFactory構(gòu)造的Session實(shí)例共享状蜗。出于性能考慮需五,避免無謂的數(shù)據(jù)庫訪問,Session在調(diào)用數(shù)據(jù)庫查詢功能之前轧坎,會(huì)先在緩存中進(jìn)行查詢宏邮。首先在第一級(jí)緩存中,通過實(shí)體類型和id進(jìn)行查找,如果第一級(jí)緩存查找命中蜜氨,且數(shù)據(jù)狀態(tài)合法械筛,則直接返回。
之后飒炎,Session會(huì)在當(dāng)前“NonExists(把無效的條件寫成一個(gè)黑名單埋哟,既然無效,那么也沒必要再查下去)”記錄中進(jìn)行查找郎汪,如果“NonExists”記錄中存在同樣的查詢條件赤赊,則返回null∩酚“NonExists”記錄了當(dāng)前Session實(shí)例在之前所有查詢操作中抛计,未能查詢到有效數(shù)據(jù)的查詢條件(相當(dāng)于一個(gè)查詢黑名單列表)。如此一來照筑,如果Session中一個(gè)無效的查詢條件重復(fù)出現(xiàn)吹截,即可迅速作出判斷,從而獲得最佳的性能表現(xiàn)凝危。
對(duì)于load方法而言波俄,如果內(nèi)部緩存中未發(fā)現(xiàn)有效數(shù)據(jù),則查詢第二級(jí)緩存蛾默,如果第二級(jí)緩存命中弟断,則返回。
如在緩存中未發(fā)現(xiàn)有效數(shù)據(jù)趴生,則發(fā)起數(shù)據(jù)庫查詢操作(Select SQL)阀趴,如經(jīng)過查詢未發(fā)現(xiàn)對(duì)應(yīng)記錄,則將此次查詢的信息在“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):首先通過id在session緩存中查找對(duì)象另假,如果存在此id的對(duì)象,直接將其返回
* b):在二級(jí)緩存中查找怕犁,找到后將 其返回边篮。
* c):如果在session緩存和二級(jí)緩存中都找不到此對(duì)象己莺,則從數(shù)據(jù)庫中加載有此ID的對(duì)象
* 因此load()方法并不總是導(dǎo)致SQL語句,只有緩存中無此數(shù)據(jù)時(shí)戈轿,才向數(shù)據(jù)庫發(fā)送SQL凌受!
*/
/** *//**
* 與get()的區(qū)別:
* 1:在立即加載對(duì)象(當(dāng)hibernate在從數(shù)據(jù)庫中取得數(shù)據(jù)組裝好一個(gè)對(duì)象后
* 會(huì)立即再從數(shù)據(jù)庫取得數(shù)據(jù)此對(duì)象所關(guān)聯(lián)的對(duì)象)時(shí),如果對(duì)象存在思杯,
* load()和get()方法沒有區(qū)別胜蛉,都可以取得已初始化的對(duì)象;但如果當(dāng)對(duì)
* 象不存在且是立即加載時(shí),使用get()方法則返回null,而使用load()則
* 拋出一個(gè)異常色乾。因此使用load()方法時(shí)誊册,要確認(rèn)查詢的主鍵ID一定是存在
* 的,從這一點(diǎn)講它沒有g(shù)et方便杈湾!
* 2:在延遲加載對(duì)象(Hibernate從數(shù)據(jù)庫中取得數(shù)據(jù)組裝好一個(gè)對(duì)象后,
* 不會(huì)立即再從數(shù)據(jù)庫取得數(shù)據(jù)組裝此對(duì)象所關(guān)聯(lián)的對(duì)象攘须,而是等到需要時(shí)漆撞,
* 都會(huì)從數(shù)據(jù)庫取得數(shù)據(jù)組裝此對(duì)象關(guān)聯(lián)的對(duì)象)時(shí),get()方法仍然使用
* 立即加載的方式發(fā)送SQL語句于宙,并得到已初始化的對(duì)象浮驳,而load()方法則
* 根本不發(fā)送SQL語句,它返回一個(gè)代理對(duì)象捞魁,直到這個(gè)對(duì)象被訪問時(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ù)庫存在谱俭,在你 聲明 TFaq tfag2=(TFaq)sess.load(TFaq.class, 300); 這句時(shí)候奉件,hibernate就干了一件事
1.查詢session緩存
2.緩存中沒有這個(gè)對(duì)象 就創(chuàng)建個(gè)代理
因?yàn)檠舆t加載需要代理來執(zhí)行 所以就創(chuàng)建了個(gè)代理
ok 到此為止 這句話就干了個(gè)這個(gè) 并沒有去數(shù)據(jù)庫交互查詢
當(dāng)你使用這個(gè)對(duì)象 比如tfag2.getTfRtitle()或get方法時(shí)候
這個(gè)時(shí)候 hibernate就去查詢二級(jí)緩存和數(shù)據(jù)庫,數(shù)據(jù)庫沒有這條數(shù)據(jù) 就拋出異常
整個(gè)load方法調(diào)用結(jié)束 load沒什么神奇 這就是他干過所有的事情
load方法講完了 我在講一下get方法工作原理
因?yàn)閔ibernate規(guī)定get方法不能使用延遲加載 所以和load還是不一樣的
TFaq tfag2=(TFaq)sess.get(TFaq.class, 300);
在創(chuàng)建這條語句時(shí)候 我們看看hibernate干了哪些事
1.get方法首先查詢session緩存 (session緩存就是hibernate的一級(jí)緩存 這個(gè)概念大家應(yīng)該清楚吧 )
2.get方法如果在session緩存中找到了該id對(duì)應(yīng)的對(duì)象昆著,如果剛好該對(duì)象前面是被代理過的县貌,如被load方法使用過,或者被其他關(guān)聯(lián)對(duì)象延遲加載過凑懂,那么返回的還是原先的代理對(duì)象煤痕,而不是實(shí)體類對(duì)象。
3.如果該代理對(duì)象還沒有加載實(shí)體數(shù)據(jù)(就是id以外的其他屬性數(shù)據(jù))接谨,那么它會(huì)查詢二級(jí)緩存或者數(shù)據(jù)庫來加載數(shù)據(jù)摆碉,但是返回的還是代理對(duì)象,只不過已經(jīng)加載了實(shí)體數(shù)據(jù)脓豪。
(這個(gè)代理實(shí)際就是空的對(duì)象 并沒有去數(shù)據(jù)庫查詢得到的 我們叫代理對(duì)象巷帝,如果 去數(shù)據(jù)庫查詢了 返回到了這個(gè)對(duì)象 我們叫實(shí)體對(duì)象 就是這個(gè)對(duì)象真實(shí)存在)
我在總結(jié)性一句話這2者區(qū)別
get方法首先查詢session緩存,沒有的話查詢二級(jí)緩存扫夜,最后查詢數(shù)據(jù)庫锅睛;反而load方法創(chuàng)建時(shí)首先查詢session緩存埠巨,沒有就創(chuàng)建代理,實(shí)際使用數(shù)據(jù)時(shí)才查詢二級(jí)緩存和數(shù)據(jù)庫
----我測(cè)試過:
在使用session.get方法后如果把session關(guān)閉的話现拒,也會(huì)出現(xiàn)懶加載異常辣垒。
那么只有在manytoone標(biāo)簽里配置 lazy="false"時(shí)異常才會(huì)解決。
也就是說上面轉(zhuǎn)載的第3條不是那么正確:返回該代理對(duì)象不錯(cuò)印蔬,但是如果該對(duì)象沒有加載實(shí)體數(shù)據(jù)勋桶,那么也會(huì)在用到時(shí)才會(huì)加載,即不會(huì)立即查詢數(shù)據(jù)庫或者二級(jí)緩存侥猬,那么你現(xiàn)在把session關(guān)閉例驹,這個(gè)對(duì)行啊沒有加載實(shí)體數(shù)據(jù)----才會(huì)出現(xiàn)懶加載異常。