hibernate如何實(shí)現(xiàn)延遲加載.doc_第1頁(yè)
hibernate如何實(shí)現(xiàn)延遲加載.doc_第2頁(yè)
hibernate如何實(shí)現(xiàn)延遲加載.doc_第3頁(yè)
hibernate如何實(shí)現(xiàn)延遲加載.doc_第4頁(yè)
hibernate如何實(shí)現(xiàn)延遲加載.doc_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

hibernate 如何實(shí)現(xiàn)延遲加載 延遲加載機(jī)制是為了避免一些無(wú)謂的性能開(kāi)銷(xiāo)而提出來(lái)的,所謂延遲加載就是當(dāng)在真正需要數(shù)據(jù)的時(shí)候,才真正執(zhí)行數(shù)據(jù)加載操作。在Hibernate中提供了對(duì)實(shí)體對(duì)象的延遲加載以及對(duì)集合的延遲加載,另外在Hibernate3中還提供了對(duì)屬性的延遲加載。下面我們就分別介紹這些種類(lèi)的延遲加載的細(xì)節(jié)。 A、實(shí)體對(duì)象的延遲加載: 如果想對(duì)實(shí)體對(duì)象使用延遲加載,必須要在實(shí)體的映射配置文件中進(jìn)行相應(yīng)的配置,如下所示: 通過(guò)將class的lazy屬性設(shè)置為true,來(lái)開(kāi)啟實(shí)體的延遲加載特性。如果我們運(yùn)行下面的代碼: User user=(User)session.load(User.class,”1”);(1) System.out.println(user.getName();(2) 當(dāng)運(yùn)行到(1)處時(shí),Hibernate并沒(méi)有發(fā)起對(duì)數(shù)據(jù)的查詢,如果我們此時(shí)通過(guò)一些調(diào)試工具(比如JBuilder2005的Debug工具),觀察此時(shí)user對(duì)象的內(nèi)存快照,我們會(huì)驚奇的發(fā)現(xiàn),此時(shí)返回的可能是User$EnhancerByCGLIB$bede8986類(lèi)型的對(duì)象,而且其屬性為null,這是怎么回事?還記得前面我曾講過(guò)session.load()方法,會(huì)返回實(shí)體對(duì)象的代理類(lèi)對(duì)象,這里所返回的對(duì)象類(lèi)型就是User對(duì)象的代理類(lèi)對(duì)象。在Hibernate中通過(guò)使用CGLIB,來(lái)實(shí)現(xiàn)動(dòng)態(tài)構(gòu)造一個(gè)目標(biāo)對(duì)象的代理類(lèi)對(duì)象,并且在代理類(lèi)對(duì)象中包含目標(biāo)對(duì)象的所有屬性和方法,而且所有屬性均被賦值為null。通過(guò)調(diào)試器顯示的內(nèi)存快照,我們可以看出此時(shí)真正的User對(duì)象,是包含在代理對(duì)象的CGLIB$CALBACK_0.target屬性中,當(dāng)代碼運(yùn)行到(2)處時(shí),此時(shí)調(diào)用user.getName()方法,這時(shí)通過(guò)CGLIB賦予的回調(diào)機(jī)制,實(shí)際上調(diào)用CGLIB$CALBACK_0.getName()方法,當(dāng)調(diào)用該方法時(shí),Hibernate會(huì)首先檢查CGLIB$CALBACK_0.target屬性是否為null,如果不為空,則調(diào)用目標(biāo)對(duì)象的getName方法,如果為空,則會(huì)發(fā)起數(shù)據(jù)庫(kù)查詢,生成類(lèi)似這樣的SQL語(yǔ)句:select * from user where id=1;來(lái)查詢數(shù)據(jù),并構(gòu)造目標(biāo)對(duì)象,并且將它賦值到CGLIB$CALBACK_0.target屬性中。 這樣,通過(guò)一個(gè)中間代理對(duì)象,Hibernate實(shí)現(xiàn)了實(shí)體的延遲加載,只有當(dāng)用戶真正發(fā)起獲得實(shí)體對(duì)象屬性的動(dòng)作時(shí),才真正會(huì)發(fā)起數(shù)據(jù)庫(kù)查詢操作。所以實(shí)體的延遲加載是用通過(guò)中間代理類(lèi)完成的,所以只有session.load()方法才會(huì)利用實(shí)體延遲加載,因?yàn)橹挥衧ession.load()方法才會(huì)返回實(shí)體類(lèi)的代理類(lèi)對(duì)象。 B、 集合類(lèi)型的延遲加載: 在Hibernate的延遲加載機(jī)制中,針對(duì)集合類(lèi)型的應(yīng)用,意義是最為重大的,因?yàn)檫@有可能使性能得到大幅度的提高,為此Hibernate進(jìn)行了大量的努力,其中包括對(duì)JDK Collection的獨(dú)立實(shí)現(xiàn),我們?cè)谝粚?duì)多關(guān)聯(lián)中,定義的用來(lái)容納關(guān)聯(lián)對(duì)象的Set集合,并不是java.util.Set類(lèi)型或其子類(lèi)型,而是net.sf.hibernate.collection.Set類(lèi)型,通過(guò)使用自定義集合類(lèi)的實(shí)現(xiàn),Hibernate實(shí)現(xiàn)了集合類(lèi)型的延遲加載。為了對(duì)集合類(lèi)型使用延遲加載,我們必須如下配置我們的實(shí)體類(lèi)的關(guān)于關(guān)聯(lián)的部分: . 通過(guò)將元素的lazy屬性設(shè)置為true來(lái)開(kāi)啟集合類(lèi)型的延遲加載特性。我們看下面的代碼: User user=(User)session.load(User.class,”1”); Collection addset=user.getAddresses(); (1) Iterator it=addset.iterator(); (2) while(it.hasNext() Address address=(Address)it.next(); System.out.println(address.getAddress(); 當(dāng)程序執(zhí)行到(1)處時(shí),這時(shí)并不會(huì)發(fā)起對(duì)關(guān)聯(lián)數(shù)據(jù)的查詢來(lái)加載關(guān)聯(lián)數(shù)據(jù),只有運(yùn)行到(2)處時(shí),真正的數(shù)據(jù)讀取操作才會(huì)開(kāi)始,這時(shí)Hibernate會(huì)根據(jù)緩存中符合條件的數(shù)據(jù)索引,來(lái)查找符合條件的實(shí)體對(duì)象。 這里我們引入了一個(gè)全新的概念數(shù)據(jù)索引,下面我們首先將接一下什么是數(shù)據(jù)索引。在Hibernate中對(duì)集合類(lèi)型進(jìn)行緩存時(shí),是分兩部分進(jìn)行緩存的,首先緩存集合中所有實(shí)體的id列表,然后緩存實(shí)體對(duì)象,這些實(shí)體對(duì)象的id列表,就是所謂的數(shù)據(jù)索引。當(dāng)查找數(shù)據(jù)索引時(shí),如果沒(méi)有找到對(duì)應(yīng)的數(shù)據(jù)索引,這時(shí)就會(huì)一條select SQL的執(zhí)行,獲得符合條件的數(shù)據(jù),并構(gòu)造實(shí)體對(duì)象集合和數(shù)據(jù)索引,然后返回實(shí)體對(duì)象的集合,并且將實(shí)體對(duì)象和數(shù)據(jù)索引納入Hibernate的緩存之中。另一方面,如果找到對(duì)應(yīng)的數(shù)據(jù)索引,則從數(shù)據(jù)索引中取出id列表,然后根據(jù)id在緩存中查找對(duì)應(yīng)的實(shí)體,如果找到就從緩存中返回,如果沒(méi)有找到,在發(fā)起select SQL查詢。在這里我們看出了另外一個(gè)問(wèn)題,這個(gè)問(wèn)題可能會(huì)對(duì)性能產(chǎn)生影響,這就是集合類(lèi)型的緩存策略。如果我們?nèi)缦屡渲眉项?lèi)型: . 這里我們應(yīng)用了配置,如果采用這種策略來(lái)配置集合類(lèi)型,Hibernate將只會(huì)對(duì)數(shù)據(jù)索引進(jìn)行緩存,而不會(huì)對(duì)集合中的實(shí)體對(duì)象進(jìn)行緩存。如上配置我們運(yùn)行下面的代碼: User user=(User)session.load(User.class,”1”); Collection addset=user.getAddresses(); Iterator it=addset.iterator(); while(it.hasNext() Address address=(Address)it.next(); System.out.println(address.getAddress(); System.out.println(“Second query”); User user2=(User)session.load(User.class,”1”); Collection it2=user2.getAddresses(); while(it2.hasNext() Address address2=(Address)it2.next(); System.out.println(address2.getAddress(); 運(yùn)行這段代碼,會(huì)得到類(lèi)似下面的輸出: Select * from user where id=1; Select * from address where user_id=1; Tianjin Dalian Second query Select * from address where id=1; Select * from address where id=2; Tianjin Dalian 我們看到,當(dāng)?shù)诙螆?zhí)行查詢時(shí),執(zhí)行了兩條對(duì)address表的查詢操作,為什么會(huì)這樣?這是因?yàn)楫?dāng)?shù)谝淮渭虞d實(shí)體后,根據(jù)集合類(lèi)型緩存策略的配置,只對(duì)集合數(shù)據(jù)索引進(jìn)行了緩存,而并沒(méi)有對(duì)集合中的實(shí)體對(duì)象進(jìn)行緩存,所以在第二次再次加載實(shí)體時(shí),Hibernate找到了對(duì)應(yīng)實(shí)體的數(shù)據(jù)索引,但是根據(jù)數(shù)據(jù)索引,卻無(wú)法在緩存中找到對(duì)應(yīng)的實(shí)體,所以Hibernate根據(jù)找到的數(shù)據(jù)索引發(fā)起了兩條select SQL的查詢操作,這里造成了對(duì)性能的浪費(fèi),怎樣才能避免這種情況呢?我們必須對(duì)集合類(lèi)型中的實(shí)體也指定緩存策略,所以我們要如下對(duì)集合類(lèi)型進(jìn)行配置: . 此時(shí)Hibernate會(huì)對(duì)集合類(lèi)型中的實(shí)體也進(jìn)行緩存,如果根據(jù)這個(gè)配置再次運(yùn)行上面的代碼,將會(huì)得到類(lèi)似如下的輸出: Select * from user where id=1; Select * from address where user_id=1; Tianjin Dalian Second query Tianjin Dalian 這時(shí)將不會(huì)再有根據(jù)數(shù)據(jù)索引進(jìn)行查詢的SQL語(yǔ)句,因?yàn)榇藭r(shí)可以直接從緩存中獲得集合類(lèi)型中存放的實(shí)體對(duì)象。 C、 屬性延遲加載: 在Hibernate3中,引入了一種新的特性屬性的延遲加載,這個(gè)機(jī)制又為獲取高性能查詢提供了有力的工具。在前面我們講大數(shù)據(jù)對(duì)象讀取時(shí),在User對(duì)象中有一個(gè)resume字段,該字段是一個(gè)java.sql.Clob類(lèi)型,包含了用戶的簡(jiǎn)歷信息,當(dāng)我們加載該對(duì)象時(shí),我們不得不每一次都要加載這個(gè)字段,而不論我們是否真的需要它,而且這種大數(shù)據(jù)對(duì)象的讀取本身會(huì)帶來(lái)很大的性能開(kāi)銷(xiāo)。在Hibernate2中,我們只有通過(guò)我們前面講過(guò)的面性能的粒度細(xì)分,來(lái)分解User類(lèi),來(lái)解決這個(gè)問(wèn)題(請(qǐng)參照那一節(jié)的論述),但是在Hibernate3中,我們可以通過(guò)屬性延遲加載機(jī)制,來(lái)使我們獲得只有當(dāng)我們真正需要操作這個(gè)字段時(shí),才去讀取這個(gè)字段數(shù)據(jù)的能力,為此我們必須如下配置我們的實(shí)體類(lèi): 通過(guò)對(duì)元素的lazy屬性設(shè)置true來(lái)開(kāi)啟屬性的延遲加載,在Hibernate3中為了實(shí)現(xiàn)屬性的延遲加載,使用了類(lèi)增強(qiáng)器來(lái)對(duì)實(shí)體類(lèi)的Class文件進(jìn)行強(qiáng)化處理,通過(guò)增強(qiáng)器的增強(qiáng),將CGLIB的回調(diào)機(jī)制邏輯,加入實(shí)體類(lèi),這里我們可以看出屬性的延遲加載,還是通過(guò)CGLIB來(lái)實(shí)現(xiàn)的。CGLIB是Apache的一個(gè)開(kāi)源工程,這個(gè)類(lèi)庫(kù)可以操縱java類(lèi)的字節(jié)碼,根據(jù)字節(jié)碼來(lái)動(dòng)態(tài)構(gòu)造符合要求的類(lèi)對(duì)象。根據(jù)上面的配置我們運(yùn)行下面的代碼: String sql=”from User user where =zx ”; Query query=session.createQuery(sql); (1) List list=query.list(); for(int i=0;ilist.size();i+) User user=(User)list.get(i); System.out.println(user.getName(); System.out.prin

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論