第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Hibernate Lazy&Fetch

1. 前言

本節(jié)和大家一起聊聊 Hibernate 中的 LazyFetch 的區(qū)別,及兩者適合的開(kāi)發(fā)場(chǎng)景。通過(guò)本節(jié)課程的學(xué)習(xí),你將了解到:

  • 什么是延遲加載;
  • 延遲加載的意義。

2. 又見(jiàn) get() 和 load()

Session 對(duì)象提供了 2 個(gè)方法用來(lái)查詢 :

  • get() 方法;
  • load()方法。

如果僅以結(jié)果為導(dǎo)向,則無(wú)法分辨兩者的差異性。

兩者如同雙胞胎,外觀雖然差異不大,但其神韻各有千秋。仔細(xì)辨別,便能發(fā)現(xiàn)屬于各自的特征。

真相只有一個(gè),查明真相的手段,也只有一種:讓代碼回答。

2.1 測(cè)試 get() 方法

Student stu=null;
try{
    // 打開(kāi)事務(wù)
    transaction = session.beginTransaction();
    //使用get()方法查詢學(xué)號(hào)為1的學(xué)生
    stu=(Student)session.get(Student.class, new Integer(1));
    System.out.println("--------------輸出學(xué)生信息------------------");
    System.out.println(stu.getStuName());
    transaction.commit();       
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}
System.out.println("***********關(guān)閉Session之后******************");
System.out.println(stu.getStuName());

如上測(cè)試代碼,和上一節(jié)課程的 get() 方法測(cè)試有區(qū)別:

  • 調(diào)用 **get()** 方法查詢編號(hào)為 1 的學(xué)生數(shù)據(jù),但會(huì)在輸出學(xué)生數(shù)據(jù)之前先輸出一條提示語(yǔ)句,作為標(biāo)識(shí)分割線;
  • 關(guān)閉 Session 對(duì)象后繼續(xù)使用查詢出來(lái)的學(xué)生數(shù)據(jù)。

查看代碼運(yùn)行結(jié)果:

select
student0_.stuId as stuId1_0_0_,
student0_.stuName as stuName2_0_0_,
student0_.stuPassword as stuPassw3_0_0_,
student0_.stuPic as stuPic4_0_0_,
student0_.stuSex as stuSex5_0_0_ 
from
Student student0_ 
where
student0_.stuId=?
--------------輸出學(xué)生信息------------------
Hibernate是老大
***********關(guān)閉Session之后******************
Hibernate是老大

結(jié)果能說(shuō)明什么問(wèn)題呢?
仔細(xì)分析輸出的日志信息:

  • 調(diào)用 get() 方法時(shí),Hibernate 就構(gòu)建了一條 Sql 語(yǔ)句。說(shuō)明,調(diào)用 get() 方法時(shí),Hibernate 就跑了一趟數(shù)據(jù)庫(kù),并拿到了開(kāi)發(fā)者指定的數(shù)據(jù);

  • 關(guān)閉 Session 對(duì)象后,程序可以繼續(xù)使用學(xué)生數(shù)據(jù)。說(shuō)明,通過(guò) get() 方法獲得的數(shù)據(jù)已經(jīng)保存到程序運(yùn)行的內(nèi)存中,不需要再依賴 Session。

想說(shuō)明什么?不想說(shuō)明什么?只是一個(gè)結(jié)論。

2.2 測(cè)試 load() 方法

把上面測(cè)試實(shí)例中的 get() 方法換成 load() 方法。

且運(yùn)行實(shí)例:

Student stu=null;
try{
    // 打開(kāi)事務(wù)
    transaction = session.beginTransaction();
    //查詢學(xué)號(hào)為1的學(xué)生
    stu=(Student)session.load(Student.class, new Integer(1));
    System.out.println("--------------輸出學(xué)生信息------------------");
    System.out.println(stu.getStuName());
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}
System.out.println("***********關(guān)閉Session之后******************");
System.out.println(stu.getStuName());

控制臺(tái)上查看實(shí)例使用結(jié)果:

--------------輸出學(xué)生信息------------------
Hibernate: 
select
student0_.stuId as stuId1_0_0_,
student0_.stuName as stuName2_0_0_,
student0_.stuPassword as stuPassw3_0_0_,
student0_.stuPic as stuPic4_0_0_,
student0_.stuSex as stuSex5_0_0_ 
from
Student student0_ 
where
student0_.stuId=?
Hibernate是老大
***********關(guān)閉Session之后******************
Hibernate是老大

得到什么結(jié)論了嗎?

現(xiàn)在開(kāi)始尋找區(qū)別。

不仔細(xì)觀察,會(huì)誤判沒(méi)有什么區(qū)別。

而其中有一個(gè)很明顯的區(qū)別就是:

調(diào)用 load ( ) 方法時(shí),Hiberante 并沒(méi)有真正的行動(dòng),只有當(dāng)執(zhí)行到下面代碼時(shí):

System.out.println(stu.getStuName());

Hibernate 才從容不迫地構(gòu)建 Sql 語(yǔ)句,往數(shù)據(jù)庫(kù)跑了一趟,獲得數(shù)據(jù),再輸出數(shù)據(jù)。

OK!再稍微改動(dòng)一下測(cè)試代碼:

//會(huì)話對(duì)象
Student stu=null;
try {
    // 打開(kāi)事務(wù)
    transaction = session.beginTransaction();
    //查詢學(xué)號(hào)為1的學(xué)生
    stu=(Student)session.load(Student.class, new Integer(1));        
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}
System.out.println("***********關(guān)閉Session之后******************");
System.out.println("--------------輸出學(xué)生信息------------------");
System.out.println(stu.getStuName());

輸出學(xué)生信息并不是在調(diào)用 load( ) 方法之后,而是關(guān)閉 Session 對(duì)象之后,結(jié)果又會(huì)怎樣?猜得出來(lái)嗎?

把你心中的猜想和下面的輸出結(jié)果比較一下。

沒(méi)想到吧,拋異常啦,拋異常沒(méi)什么大驚小怪的,異常是為了告訴你錯(cuò)誤原因。查看異常信息,從中找出原因:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
省略其它若干……

不要望而生畏,都是紙老虎。找出關(guān)鍵詞:

could not initialize proxy - no Session

初看字面意思:不能初始化代理,沒(méi)有 Session 對(duì)象。

什么意思?

到了好好解釋這個(gè)原因的時(shí)候:

調(diào)用 load( ) 方法時(shí),Hibernate 根本沒(méi)有如你所期望一樣,往數(shù)據(jù)庫(kù)跑。但是又不想讓你知道它沒(méi)去,或是怕你擔(dān)心它是否能完成這份工作。于是 Hibernate 為你提供了一個(gè) 代理對(duì)象。

這里會(huì)涉及到代理設(shè)計(jì)模式!為不影響主題學(xué)習(xí),代理設(shè)計(jì)模式相關(guān)內(nèi)容自己了解一下。

什么是代理對(duì)象?

通俗講就是說(shuō)外觀和開(kāi)發(fā)者所期望的對(duì)象一樣,但沒(méi)有實(shí)質(zhì)性數(shù)據(jù)。
再通俗點(diǎn),就是一個(gè)替身。有其外形,而無(wú)內(nèi)涵。
再通俗講:哦,你已經(jīng)明白了。

Hibernate 這是演的哪一出?這不是擺明欺負(fù)人嗎?

別誤會(huì),這是 Hibernate 的善意之舉!善意從何談起呀!別急!

只有當(dāng)開(kāi)發(fā)者真正需要數(shù)據(jù)時(shí):

System.out.println(stu.getStuName());

Hibernate 才會(huì)構(gòu)建 Sql 語(yǔ)句,往數(shù)據(jù)庫(kù)跑一趟,獲得真正的數(shù)據(jù)。

但是,執(zhí)行 Sql 語(yǔ)句是一定要在 Session 的生命周期之內(nèi),如果:

session.close();

通往數(shù)據(jù)庫(kù)的橋梁被拆了。Hibernate 也無(wú)能為力,只能以異常的方式告訴你:

no Session!臣妾做不到呀。

測(cè)試 get()、load() 方法的輸出結(jié)果已經(jīng)表明了兩者的差異性:

  • get() 方法言行一致,說(shuō)出手呀便出手。開(kāi)發(fā)者一調(diào)用,便快馬加鞭,從數(shù)據(jù)庫(kù)中獲得數(shù)據(jù),保存到學(xué)生對(duì)象中,只要學(xué)生對(duì)象在,數(shù)據(jù)也就在;
  • load() 方法,看起來(lái)倒像是說(shuō)一套,做一套的主。并不會(huì)立馬行事,而是創(chuàng)建一個(gè)學(xué)生代理對(duì)象,提供和開(kāi)發(fā)者期待的學(xué)生數(shù)據(jù)對(duì)象相同的方法接口,不影響開(kāi)發(fā)者調(diào)用。只有當(dāng)開(kāi)發(fā)者真正需要數(shù)據(jù)時(shí),才會(huì)說(shuō),好的,我去看一下數(shù)據(jù)庫(kù)。

故而,使用 load() 時(shí)就需要特別注意,在 Hibernate 取數(shù)據(jù)庫(kù)之前,千萬(wàn)別關(guān)閉通向數(shù)據(jù)庫(kù)的橋梁:Session 對(duì)象。

Session 家里有 2 個(gè)可用于查詢的兄弟:

  • get() 是老實(shí)人,言行一致。
  • load() 有點(diǎn)小調(diào)皮,有時(shí)搞點(diǎn)惡作劇,但心思并不壞。如果真正理解它的意圖,在特定的環(huán)境下,可能會(huì)感動(dòng)到你。

其實(shí)兩兄弟都很有趣。

3. 延遲加載

延遲加載?不是在聊 get()load() 方法嗎,不是聊得好好的嘛!咋的,中場(chǎng)休息呀。

3.1 什么是延遲加載

什么是延遲加載?前面的測(cè)試結(jié)論已經(jīng)給出了答案。

使用 Hibernate 獲取數(shù)據(jù)時(shí),有時(shí),Hibernate 并不急著去數(shù)據(jù)庫(kù),而是等到開(kāi)發(fā)者真正需要數(shù)據(jù)時(shí)才會(huì)跑一趟數(shù)據(jù)庫(kù)。

load() 方法 和 get() 方法的基礎(chǔ)區(qū)別:

  • load() 支持延遲加載(Lazy);

意思是,別急,你需要時(shí)我再去拿數(shù)據(jù)。如果沒(méi)有拿到數(shù)據(jù),則會(huì)拋出異常。

  • get() 方法不支持延遲加載,而是(Fetch),如果沒(méi)有拿到數(shù)據(jù),則返回 null 。

什么時(shí)候使用 get(),什么時(shí)候使用 load()。只有需求才能告訴你如何權(quán)衡,沒(méi)有絕對(duì)的忠告。

3.2 延遲加載的意義

答案很簡(jiǎn)單:錯(cuò)峰出行,需時(shí)索取。

數(shù)據(jù)庫(kù)系統(tǒng)的迎接能力終歸是有限的。面對(duì)同時(shí)有很多數(shù)據(jù)請(qǐng)求時(shí),就會(huì)造成擁堵。并不是所有的數(shù)據(jù)請(qǐng)求會(huì)在它的邏輯中立即使用數(shù)據(jù)。

于是,就可以使用延遲加載技術(shù),暫緩數(shù)據(jù)請(qǐng)求,真正需要時(shí),或錯(cuò)開(kāi)數(shù)據(jù)庫(kù)系統(tǒng)的訪問(wèn)高峰期后再訪問(wèn)。

圖片描述

在真實(shí)的企業(yè)級(jí)項(xiàng)目中,一個(gè)業(yè)務(wù)邏輯往往是借助于多個(gè)組件一起協(xié)作完成的。

圖片描述

Hibernate 作為數(shù)據(jù)請(qǐng)求框架,充當(dāng)數(shù)據(jù)提供者角色,本身并不處理數(shù)據(jù)。數(shù)據(jù)的使用延遲到了數(shù)據(jù)加工組件之中。

于是,Hibernate 用不著立即造訪數(shù)據(jù)庫(kù),先給數(shù)據(jù)加工組件提供一個(gè)代理對(duì)象,等數(shù)據(jù)加工組件真正需要數(shù)據(jù)時(shí)再訪問(wèn)數(shù)據(jù)庫(kù)也不遲。

延遲加載是 Hibernate 中的性能優(yōu)化技術(shù),不要誤會(huì)它是在使什么小心眼。完全是一番好意。

哲學(xué)上講世界是平衡的,一頭變輕,另一頭就會(huì)變重??偰芰肯牟蛔儭?/p>

延遲加載技術(shù)提供了一種性能優(yōu)化方式(變輕了),但在還沒(méi)有真正獲取數(shù)據(jù)之前,不能關(guān)閉 Session 對(duì)象(生命周期延長(zhǎng),變重了)算是平衡制約吧。

4. 小結(jié)

本節(jié)課聊到了 Hibernate 中一個(gè)很重要的概念:延遲加載,是一種性能優(yōu)化技術(shù)。讓開(kāi)發(fā)者在真正需要數(shù)據(jù)的時(shí)候才進(jìn)入到數(shù)據(jù)庫(kù)。

Session 提供的 load() 方法支持延遲加載。但是,千萬(wàn)別以為延遲加載僅僅是 load() 方法的專利。

延遲加載是性能優(yōu)化技術(shù),Hibernate 在設(shè)計(jì)時(shí),凡是考慮有必要使用的地方都會(huì)有延遲加載的身影。