hibernate(三)[延遲加載]

這就是 PersistentSet 集合跟據 owner 屬性去抓取特定 Address 記錄的 SQL 語句。此時可以從 Eclipse 的 Variables 窗口看到圖 3 所示的輸出:

圖 3. 已加載的集合屬性值

從圖 3 可以看出,此時的 addresses 屬性已經被初始化了,集合里包含了 2 個 Address 對象,這正是 Person 實體所關聯的兩個 Address 對象。

通過上面介紹可以看出,Hibernate 對于 Set 屬性延遲加載關鍵就在于 PersistentSet 實現類。在延遲加載時,開始 PersistentSet 集合里并不持有任何元素。但 PersistentSet 會持有一個 Hibernate Session,它可以保證當程序需要訪問該集合時“立即”去加載數據記錄,并裝入集合元素。

與 PersistentSet 實現類類似的是,Hibernate 還提供了 PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等實現類,它們的功能與 PersistentSet 的功能大致類似。

熟悉 Hibernate 集合屬性讀者應該記得:Hibernate 要求聲明集合屬性只能用 Set、List、Map、SortedSet、SortedMap 等接口,而不能用 HashSet、ArrayList、HashMap、TreeSet、TreeMap 等實現類,其原因就是因為 Hibernate 需要對集合屬性進行延遲加載,而 Hibernate 的延遲加載是依靠 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 來完成的——也就是說,Hibernate 底層需要使用自己的集合實現類來完成延遲加載,因此它要求開發者必須用集合接口、而不是集合實現類來聲明集合屬性。

Hibernate 對集合屬性默認采用延遲加載,在某些特殊的情況下,為 <set.../>、<list.../>、<map.../> 等元素設置 lazy="false"屬性來取消延遲加載。


關聯實體的延遲加載

默認情況下,Hibernate 也會采用延遲加載來加載關聯實體,不管是一對多關聯、還是一對一關聯、多對多關聯,Hibernate 默認都會采用延遲加載。
對于關聯實體,可以將其分為兩種情況:

<li>關聯實體是多個實體時(包括一對多、多對多):此時關聯實體將以集合的形式存在,Hibernate 將使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合來管理延遲加載的實體。這就是前面所介紹的情形。
<li>關聯實體是單個實體時(包括一對一、多對一):當 Hibernate 加載某個實體時,延遲的關聯實體將是一個動態生成代理對象。

當關聯實體是單個實體時,也就是使用 <many-to-one.../> 或 <one-to-one.../> 映射關聯實體的情形,這兩個元素也可通過 lazy 屬性來指定延遲加載。

下面例子把 Address 類也映射成持久化類,此時 Address 類也變成實體類,Person 實體與 Address 實體形成一對多的雙向關聯。此時的映射文件代碼如下:

<?xml version="1.0" encoding="GBK"?> 
 <!-- 指定 Hibernate 的 DTD 信息 --> 
 <!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
 <hibernate-mapping package="org.crazyit.app.domain"> 
 <!-- 映射 Person 持久化類 --> 
 <class name="Person" table="person_inf"> 
 <!-- 映射標識屬性 id --> 
 <id name="id" column="person_id"> 
 <!-- 定義主鍵生成器策略 --> 
 <generator class="identity"/> 
 </id> 
 <!-- 用于映射普通屬性 --> 
 <property name="name" type="string"/> 
 <property name="age" type="int"/> 
 <!-- 映射集合屬性,集合元素是其他持久化實體
沒有指定 cascade 屬性,指定不控制關聯關系 --> 
 <set name="addresses" inverse="true"> 
 <!-- 指定關聯的外鍵列 --> 
 <key column="person_id"/> 
 <!-- 用以映射到關聯類屬性 --> 
 <one-to-many class="Address"/> 
 </set> 
 </class> 

 <!-- 映射 Address 持久化類 --> 
 <class name="Address" table="address_inf"> 
 <!-- 映射標識屬性 addressId --> 
 <id name="addressId" column="address_id"> 
 <!-- 指定主鍵生成器策略 --> 
 <generator class="identity"/> 
 </id> 
 <!-- 映射普通屬性 detail --> 
 <property name="detail"/> 
 <!-- 映射普通屬性 zip --> 
 <property name="zip"/> 
 <!-- 必須指定列名為 person_id, 
與關聯實體中 key 元素的 column 屬性值相同 --> 
 <many-to-one name="person" class="Person"
 column="person_id" not-null="true"/> 
 </class> 
 </hibernate-mapping> 

接下來程序通過如下代碼片段來加載 ID 為 1 的 Person 實體:

// 打開上下文相關的 Session 
 Session session = sf.getCurrentSession(); 
 Transaction tx = session.beginTransaction(); 
 Address address = (Address) session.get(Address.class , 1); //<1> 
 System.out.println(address.getDetail()); 

為了看到 Hibernate 加載 Address 實體時對其關聯實體的處理,我們在 <1>號代碼處設置一個斷點,在 Eclipse 中進行 Debug,此時可以看到 Eclipse 的 Console 窗口輸出如下 SQL 語句:

select 
        address0_.address_id as address1_1_0_, 
        address0_.detail as detail1_0_, 
        address0_.zip as zip1_0_, 
        address0_.person_id as person4_1_0_ 
    from 
        address_inf address0_ 
    where 
        address0_.address_id=? 

從這條 SQL 語句不難看出,Hibernate 加載 Address 實體對應的數據表抓取記錄,并未從 Person 實體對應的數據表中抓取記錄,這是延遲加載發揮了作用。
從 Eclipse 的 Variables 窗口看到如圖 4 所示的輸出:

圖 4. 延遲加載的實體

從圖 4 可以清楚地看到,此時 Address 實體所關聯的 Person 實體并不是 Person 對象,而是一個 Person_$$_javassist_0 類的實例,這個類是 Hibernate 使用 Javassist 項目動態生成的代理類——當 Hibernate 延遲加載關聯實體時,將會采用 Javassist 生成一個動態代理對象,這個代理對象將負責代理“暫未加載”的關聯實體。

只要應用程序需要使用“暫未加載”的關聯實體,Person_$$_javassist_0 代理對象會負責去加載真正的關聯實體,并返回實際的關聯實體——這就是最典型的代理模式。
單擊圖 4 所示 Variables 窗口中的 person 屬性(也就是在調試模式下強行使用 person 屬性),此時看到 Eclipse 的 Console 窗口輸出如下的 SQL 語句:

select 
        person0_.person_id as person1_0_0_, 
        person0_.name as name0_0_, 
        person0_.age as age0_0_ 
    from 
        person_inf person0_ 
    where 
        person0_.person_id=? 

上面 SQL 語句就是去抓取“延遲加載”的關聯實體的語句。此時可以看到 Variables 窗口輸出圖 5 所示的結果:

圖 5. 已加載的實體

Hibernate 采用“延遲加載”管理關聯實體的模式,其實就在加載主實體時,并未真正去抓取關聯實體對應數據,而只是動態地生成一個對象作為關聯實體的代理。當應用程序真正需要使用關聯實體時,代理對象會負責從底層數據庫抓取記錄,并初始化真正的關聯實體。

在 Hibernate 的延遲加載中,客戶端程序開始獲取的只是一個動態生成的代理對象,而真正的實體則委托給代理對象來管理——這就是典型的代理模式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容

  • Hibernae 的延遲加載是一個非常常用的技術,實體的集合屬性默認會被延遲加載,實體所關聯的實體默認也會被延遲加...
    rollAway閱讀 430評論 0 0
  • 什么是懶加載?他的作用? 延遲加載,也叫懶加載,它是hibernate為提高程序執行效率而提供的一種機制,即只有真...
    FTOLsXD閱讀 251評論 0 1
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,812評論 18 139
  • 文\落雪 可能作為一個寫作的菜鳥,我不應該起個這么大的標題,更不應該對如何寫作這件事兒指...
    落雪有晴空閱讀 1,262評論 9 13
  • 【CSS簡介】 Css它對html來講做出了很多的貢獻其中有一個很重要的貢獻就是將所有標簽中跟樣式有關的屬性都集中...
    黑色的夜閱讀 258評論 0 0