Hibernate3消極式載入機制

來源:互聯網
上載者:User
消極式載入: 首先說明Hibernate3消極式載入只多其中的load,get,find一些內值方法有用,對hql等寫sql的無效。    消極式載入機制是為了避免一些無謂的效能開銷而提出來的,所謂消極式載入就是當在真正需要資料的時候,才真正執行資料載入操作。在 Hibernate 中提供了對實體物件的消極式載入以及對集合的消極式載入,另外在 Hibernate3 中還提供了對屬性的消極式載入。下面我們就分別介紹這些種類的消極式載入的細節。 A、 實體物件的消極式載入: 如果想對實體物件使用消極式載入,必須要在實體的映射設定檔中進行相應的配置,如下所示: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user” lazy=”true”>    …… </class> </hibernate-mapping> 通過將 class lazy 屬性設定為 true ,來開啟實體的消極式載入特性。如果我們運行下面的代碼: User user=(User)session.load(User.class,”1”); 1 System.out.println(user.getName()); 2 當運行到 (1) 處時, Hibernate 並沒有發起對資料的查詢,如果我們此時通過一些調試工具 ( 比如 JBuilder2005 Debug 工具 ) ,觀察此時 user 對象的記憶體快照,我們會驚奇的發現,此時返回的可能是 User$EnhancerByCGLIB$$bede8986 類型的對象,而且其屬性為 null, 這是怎麼回事。還記得前面我曾講過 session.load() 方法,會返回實體物件的代理類對象,這裡所返回的物件類型就是 User 對象的代理類對象。在 Hibernate 中通過使用 CGLIB, 來實現動態構造一個目標對象的代理類對象,並且在代理類對象中包含目標對象的所有屬性和方法,而且所有屬性均被賦值為 null 。通過調試器顯示的記憶體快照,我們可以看出此時真正的 User 對象,是包含在代理對象的 CGLIB$CALBACK_0.target 屬性中,當代碼運行到( 2 )處時,此時調用 user.getName() 方法,這時通過 CGLIB 賦予的回調機制,實際上調用 CGLIB$CALBACK_0.getName() 方法,當調用該方法時, Hibernate 會首先檢查 CGLIB$CALBACK_0.target 屬性是否為 null ,如果不為空白,則調用目標對象的 getName 方法,如果為空白,則會發起資料庫查詢,產生類似這樣的 SQL 語句: select * from user where id=’1’; 來查詢資料,並構造目標對象,並且將它賦值到 CGLIB$CALBACK_0.target 屬性中。    這樣,通過一個中間代理對象, Hibernate 實現了實體的消極式載入,只有當使用者真正發起獲得實體物件屬性的動作時,才真正會發起資料庫查詢操作。所以實體的消極式載入是用通過中間代理類完成的,所以只有 session.load() 方法才會利用實體消極式載入,因為只有 session.load() 方法才會返回實體類的代理類對象。 B、        集合類型的消極式載入: Hibernate 的消極式載入機制中,針對集合類型的應用,意義是最為重大的,因為這有可能使效能得到大幅度的提高,為此 Hibernate 進行了大量的努力,其中包括對 JDK Collection 的獨立實現,我們在一對多關聯中,定義的用來容納關聯對象的 Set 集合,並不是 java.util.Set 類型或其子類型,而是 net.sf.hibernate.collection.Set 類型,通過使用自訂集合類的實現, Hibernate 實現了集合類型的消極式載入。為了對集合類型使用消極式載入,我們必須如下配置我們的實體類的關於關聯的部分: <hibernate-mapping>    <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set>    </class> </hibernate-mapping> 通過將 <set> 元素的 lazy 屬性設定為 true 來開啟集合類型的消極式載入特性。我們看下面的代碼: 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()); } 當程式執行到 (1) 處時,這時並不會發起對關聯資料的查詢來載入關聯資料,只有運行到 (2) 處時,真正的資料讀取操作才會開始,這時 Hibernate 會根據緩衝中合格資料索引,來尋找合格實體物件。 這裡我們引入了一個全新的概念——資料索引,下面我們首先將接一下什麼是資料索引。在 Hibernate 中對集合類型進行緩衝時,是分兩部分進行緩衝的,首先緩衝集合中所有實體的 id 列表,然後緩衝實體物件,這些實體物件的 id 列表,就是所謂的資料索引。當尋找資料索引時,如果沒有找到對應的資料索引,這時就會一條 select SQL 的執行,獲得合格資料,並構造實體物件集合和資料索引,然後返回實體物件的集合,並且將實體物件和資料索引納入 Hibernate 的緩衝之中。另一方面,如果找到對應的資料索引,則從資料索引中取出 id 列表,然後根據 id 在緩衝中尋找對應的實體,如果找到就從緩衝中返回,如果沒有找到,在發起 select SQL 查詢。在這裡我們看出了另外一個問題,這個問題可能會對效能產生影響,這就是集合類型的緩衝策略。如果我們如下配置集合類型: <hibernate-mapping>    <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <cache usage=”read-only”/> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set>    </class> </hibernate-mapping> 這裡我們應用了 <cache usage=”read-only”/> 配置,如果採用這種策略來配置集合類型, Hibernate 將只會對資料索引進行緩衝,而不會對集合中的實體物件進行緩衝。如上配置我們運行下面的代碼: 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()); } 運行這段代碼,會得到類似下面的輸出: 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 我們看到,當第二次執行查詢時,執行了兩條對 address 表的查詢操作,為什麼會這樣。這是因為當第一次載入實體後,根據集合類型緩衝策略的配置,只對集合資料索引進行了緩衝,而並沒有對集合中的實體物件進行緩衝,所以在第二次再次載入實體時, Hibernate 找到了對應實體的資料索引,但是根據資料索引,卻無法在緩衝中找到對應的實體,所以 Hibernate 根據找到的資料索引發起了兩條 select SQL 的查詢操作,這裡造成了對效能的浪費,怎樣才能避免這種情況呢。我們必須對集合類型中的實體也指定緩衝策略,所以我們要如下對集合類型進行配置: <hibernate-mapping>    <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <cache usage=”read-write”/> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set>    </class> </hibernate-mapping> 此時 Hibernate 會對集合類型中的實體也進行緩衝,如果根據這個配置再次運行上面的代碼,將會得到類似如下的輸出: Select * from user where id=’1’; Select * from address where user_id=’1’; Tianjin Dalian Second query…… Tianjin Dalian 這時將不會再有根據資料索引進行查詢的 SQL 語句,因為此時可以直接從緩衝中獲得集合類型中存放的實體物件。 C、       屬性消極式載入:    Hibernate3 中,引入了一種新的特性——屬性的消極式載入,這個機制又為擷取高效能查詢提供了有力的工具。在前面我們講大資料對象讀取時,在 User 對象中有一個 resume 欄位,該欄位是一個 java.sql.Clob 類型,包含了使用者的簡曆資訊,當我們載入該對象時,我們不得不每一次都要載入這個欄位,而不論我們是否真的需要它,而且這種大資料對象的讀取本身會帶來很大的效能開銷。在 Hibernate2 中,我們只有通過我們前面講過的面效能的粒度細分,來分解 User 類,來解決這個問題(請參照那一節的論述),但是在 Hibernate3 中,我們可以通過屬性消極式載入機制,來使我們獲得只有當我們真正需要操作這個欄位時,才去讀取這個欄位資料的能力,為此我們必須如下配置我們的實體類: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user”> …… <property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/>    </class> </hibernate-mapping> 通過對 <property> 元素的 lazy 屬性設定 true 來開啟屬性的消極式載入,在 Hibernate3 中為了實現屬性的消極式載入,使用了類增強器來對實體類的 Class 檔案進行強化處理,通過增強器的增強,將 CGLIB 的回調機制邏輯,加入實體類,這裡我們可以看出屬性的消極式載入,還是通過 CGLIB 來實現的。 CGLIB Apache 的一個開源工程,這個類庫可以操縱 java 類的位元組碼,根據位元組碼來動態構造符合要求的類對象。根據上面的配置我們運行下面的代碼: String sql=”from User user where user.name=’zx’ ”; Query query=session.createQuery(sql);   (1) List list=query.list(); for(int i=0;i<list.size();i++){ User user=(User)list.get(i); System.out.println(user.getName()); System.out.println(user.getResume());   (2) } 當執行到 (1) 處時,會產生類似如下的 SQL 語句: Select id,age,name from user where name=’zx’; 這時 Hibernate 會檢索 User 實體中所有非消極式載入屬性對應的欄位資料,當執行到 (2) 處時,會產生類似如下的 SQL 語句: Select resume from user where id=’1’; 這時會發起對 resume 欄位資料真正的讀取操作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.