教你如何在Hibernate中實(shí)例化集合和代理
本文向大家介紹Hibernate中實(shí)例化集合和代理,可能好多人還不了解Hibernate中實(shí)例化集合和代理,沒(méi)有關(guān)系,看完本文你肯定有不少收獲,希望本文能教會(huì)你更多東西。
Hibernate中實(shí)例化集合和代理在Session范圍之外訪問(wèn)未初始化的集合或代理,Hibernate將會(huì)拋出LazyInitializationException異常。 也就是說(shuō),在分離狀態(tài)下,訪問(wèn)一個(gè)實(shí)體所擁有的集合,或者訪問(wèn)其指向代理的屬性時(shí),會(huì)引發(fā)此異常。
有時(shí)候我們需要保證某個(gè)代理或者集合在Session關(guān)閉前就已經(jīng)被初始化了。 當(dāng)然,我們可以通過(guò)強(qiáng)行調(diào)用cat.getSex()或者cat.getKittens().size()之類的方法來(lái)確保這一點(diǎn)。 但是這樣的程序會(huì)造成讀者的疑惑,也不符合通常的代碼規(guī)范。
靜態(tài)方法Hibernate.initialized() 為你的應(yīng)用程序提供了一個(gè)便捷的途徑來(lái)延遲加載集合或代理。 只要它的Session處于open狀態(tài),Hibernate.initialize(cat) 將會(huì)為cat強(qiáng)制對(duì)代理實(shí)例化。 同樣,Hibernate.initialize( cat.getKittens() ) 對(duì)kittens的集合具有同樣的功能。
還有另外一種選擇,就是保持Session一直處于open狀態(tài),直到所有需要的集合或代理都被載入。 在某些應(yīng)用架構(gòu)中,特別是對(duì)于那些使用Hibernate進(jìn)行數(shù)據(jù)訪問(wèn)的代碼,以及那些在不同應(yīng)用層和不同物理進(jìn)程中使用Hibernate的代碼。 在集合實(shí)例化時(shí),如何保證Session處于open狀態(tài)經(jīng)常會(huì)是一個(gè)問(wèn)題。有兩種方法可以解決此問(wèn)題:
在一個(gè)基于Web的應(yīng)用中,可以利用servlet過(guò)濾器(filter),在用戶請(qǐng)求(request)結(jié)束、頁(yè)面生成 結(jié)束時(shí)關(guān)閉Session(這里使用了在展示層保持打開(kāi)Session模式(Open Session in View)), 當(dāng)然,這將依賴于應(yīng)用框架中異常需要被正確的處理。
在返回界面給用戶之前,乃至在生成界面過(guò)程中發(fā)生異常的情況下, 正確關(guān)閉Session和結(jié)束事務(wù)將是非常重要的, 請(qǐng)參見(jiàn)Hibernate wiki上的"Open Session in View"模式,你可以找到示例。
在一個(gè)擁有單獨(dú)業(yè)務(wù)層的應(yīng)用中,業(yè)務(wù)層必須在返回之前,為web層“準(zhǔn)備”好其所需的數(shù)據(jù)集合。這就意味著 業(yè)務(wù)層應(yīng)該載入所有表現(xiàn)層/web層所需的數(shù)據(jù),并將這些已實(shí)例化完畢的數(shù)據(jù)返回。
通常,應(yīng)用程序應(yīng)該 為web層所需的每個(gè)集合調(diào)用Hibernate.initialize()(這個(gè)調(diào)用必須發(fā)生咱session關(guān)閉之前); 或者使用帶有FETCH從句,或FetchMode.JOIN的Hibernate查詢, 事先取得所有的數(shù)據(jù)集合。
如果你在應(yīng)用中使用了Command模式,代替Session Facade , 那么這項(xiàng)任務(wù)將會(huì)變得簡(jiǎn)單的多。
你也可以通過(guò)merge()或lock()方法,在訪問(wèn)未實(shí)例化的集合(或代理)之前, 為先前載入的對(duì)象綁定一個(gè)新的Session。
顯然,Hibernate將不會(huì),也不應(yīng)該自動(dòng)完成這些任務(wù),因?yàn)檫@將引入一個(gè)特殊的事務(wù)語(yǔ)義。
有時(shí)候,你并不需要完全實(shí)例化整個(gè)大的集合,僅需要了解它的部分信息(例如其大小)、或者集合的部分內(nèi)容。
你可以使用集合過(guò)濾器得到其集合的大小,而不必實(shí)例化整個(gè)集合:
- ( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()
這里的createFilter()方法也可以被用來(lái)有效的抓取集合的部分內(nèi)容,而無(wú)需實(shí)例化整個(gè)集合:
- s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();
【編輯推薦】