性能優(yōu)化策略

1.     簡(jiǎn)介

版本:Hibernate3.2

1.1  目的

1.2  范圍

1.3  定義、首字母縮寫詞和縮略語

1.4  參考資料

1.5  概述

2.     緩存策略

2.1  什么是緩存?

Hibernate將數(shù)據(jù)臨時(shí)存放在內(nèi)存中,以便加快數(shù)據(jù)的存取速度。為此,我們可以想象,緩存的實(shí)現(xiàn),就類似于一個(gè)Map對(duì)象,首先需要一個(gè)key,以便定位相應(yīng)被緩存的數(shù)據(jù),而它的value值,便是被緩存的數(shù)據(jù)。

 

2.2  一級(jí)緩存

session級(jí)別的緩存,隨著session的關(guān)閉而消失,load/iterator操作,會(huì)從一級(jí)緩存中查找數(shù)據(jù),如果找不到,再到數(shù)據(jù)庫里面查找。Query.list操作,如果沒有配置查詢緩存,將直接從數(shù)據(jù)庫中獲取數(shù)據(jù)。

 

2.3  二級(jí)緩存

SessionFactory級(jí)別的緩存。默認(rèn)的情況下是打開的。這是一個(gè)全局緩存策略。它可以對(duì)對(duì)象的數(shù)據(jù)進(jìn)行全局緩存

2.4  查詢緩存

即對(duì)查詢的結(jié)果集進(jìn)行緩存處理,以便下次相同條件相同HQL的情況下可以直接從緩存中獲取數(shù)據(jù)。

 

3.     二級(jí)緩存

3.1.1           如何打開二級(jí)緩存?

需要更改hibernate配置文件:

1、  打開二級(jí)緩存(默認(rèn)情況下是打開的)

a)       true

2、  指定緩存策略提供商

a)       org.hibernate.cache.EhCacheProvider

 

3.1.2           二級(jí)緩存是對(duì)對(duì)象數(shù)據(jù)的緩存

為了讓hibernate對(duì)對(duì)象進(jìn)行緩存,你必須指定需要緩存哪些類的對(duì)象,這有兩種方法可以達(dá)到這個(gè)目的:

1、  hibernate配置文件中指定,如

2、  在類的映射文件中(即標(biāo)簽下指定),如

read-only/>

 

如果你打開了對(duì)對(duì)象的緩存,那么,所有對(duì)這個(gè)對(duì)象的查詢操作的結(jié)果,都會(huì)被緩存起來。Hibernate將使用對(duì)象的鍵值作為緩存的key值,對(duì)象的數(shù)據(jù)作為緩存的value值。

打開了對(duì)象緩存,只有在對(duì)對(duì)象進(jìn)行查詢操作的時(shí)候,才會(huì)起作用,如createQuery(from Student).iterate()

 

3.1.3           緩存策略

緩存有幾種形式,可以在映射文件中配置:read-only(只讀,適用于很少變更的靜態(tài)數(shù)據(jù)/歷史數(shù)據(jù))nonstrict-read-writeread-write(比較普遍的形式,效率一般)transactional(JTA中,且支持的緩存產(chǎn)品較少)

 

 

4.     查詢緩存

 

查詢緩存的作用,是對(duì)list操作的查詢結(jié)果集進(jìn)行緩存!

 

我們使用list操作的時(shí)候,如果啟用了查詢緩存hibernate將根據(jù)當(dāng)前查詢的HQL語句(及其參數(shù)值)計(jì)算出一個(gè)緩存的key值;查詢結(jié)果集,將作為緩存的value值(但如果查詢結(jié)果集是一個(gè)對(duì)象結(jié)果集的話,其緩存的value值是對(duì)象的ID集合,而不是對(duì)象集合本身)。

 

可以在hibernate配置文件中添加:

true

以便打開查詢緩存。

 

查詢緩存,對(duì)對(duì)象查詢,將緩存其ID列表;對(duì)普通查詢,將緩存整個(gè)數(shù)據(jù)集合。所以,對(duì)于對(duì)象查詢,需要配合二級(jí)緩存來使用。

 

在打開了查詢緩存之后,需要注意,調(diào)用query.list()操作之前,必須顯式調(diào)用query.setCachable(true)來標(biāo)識(shí)某個(gè)查詢使用緩存。

 

 

5.     關(guān)于loadgetiteratelist操作在緩存中的作用

5.1  Load/get

這個(gè)方法,用于加載某個(gè)對(duì)象。如果打開了二級(jí)緩存,加載的對(duì)象數(shù)據(jù)將會(huì)被緩存。緩存的key是對(duì)象的ID,緩存的value是對(duì)象的值。

5.2  Iterate

使用iterate進(jìn)行查詢,分成兩種不同的情況:

1、  使用iterate方法進(jìn)行對(duì)象查詢,如createQuery(from Student).iterate(),這個(gè)時(shí)候,如果打開了二級(jí)緩存,其加載的對(duì)象集合,將會(huì)被緩存。緩存的key為對(duì)象的ID值,緩存的value是對(duì)象的數(shù)據(jù)。

2、  使用iterate方法進(jìn)行其它查詢,如createQuery(select name,sex from Student).iterate(),這個(gè)時(shí)候,不管有沒有打開二級(jí)緩存(以及查詢緩存),其查詢的結(jié)果集都不會(huì)進(jìn)行緩存

 

5.3  List

查詢緩存只對(duì)list操作起作用

使用List進(jìn)行查詢,也分成兩種情況:

1、  使用list方法進(jìn)行對(duì)象查詢,如createQuery(from Student).list(),這個(gè)時(shí)候,

a)       如果打開了查詢緩存,并使用查詢緩存(query.setCachable(true);),hibernate將對(duì)對(duì)象的ID列表進(jìn)行緩存

b)       如果同時(shí)打開了這個(gè)對(duì)象的二級(jí)緩存,那么hibernate就會(huì)將這個(gè)對(duì)象的數(shù)據(jù)加入二級(jí)緩存中。

2、  使用list方法進(jìn)行普通查詢,如createQuery(select name,sex from Student).list(),這個(gè)時(shí)候,

a)       如果打開了查詢緩存,并使用查詢緩存(query.setCachable(true);),hibernate將對(duì)查詢的結(jié)果集進(jìn)行緩存

b)       不管有沒有打開二級(jí)緩存,二級(jí)緩存的任何設(shè)置,對(duì)這種類型的查詢,不會(huì)產(chǎn)生任何影響(因?yàn)槎?jí)緩存只對(duì)對(duì)象的數(shù)據(jù)進(jìn)行緩存,而不是某些查詢結(jié)果集)

 

 

5.4  Session如何與二級(jí)緩存交互?

Session接口通過CacheMode來定制與二級(jí)緩存之間的交互方法:

 

 

 

6.     抓取策略

 

抓取策略,即如何獲取數(shù)據(jù)的策略。

 

下面以下述模型為例:

 

班級(jí)與學(xué)生模型,之間是一對(duì)多雙向關(guān)聯(lián):

 

<hibernate-mapping>

    <class name="com.bjsxt.hibernate.one2many.Classes" lazy="false" batch-size="10" table="T_Classes">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

       <set name="students" inverse="true" lazy="false" cascade="all" >

           <key column="classesid"/>

           <one-to-many class="com.bjsxt.hibernate.one2many.Student"/>

       </set>

    </class>

   

    <class name="com.bjsxt.hibernate.one2many.Student" lazy="false" table="T_Student">

      

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name" length="20"/>

       <property name="sex" length="10" />

       <many-to-one lazy="false" name="classes" column="classesid"/>

    </class>

</hibernate-mapping>

 

 

 

·         連接抓取(Join fetching - Hibernate通過 在SELECT語句使用OUTER JOIN(外連接)來 獲得對(duì)象的關(guān)聯(lián)實(shí)例或者關(guān)聯(lián)集合。 連接抓取策略可以被定義在或集合(如)標(biāo)簽上。這種抓取策略,對(duì)load/get操作有效。

·         如在Student標(biāo)簽上設(shè)置fetch=”join”,當(dāng)我們load/get一個(gè)Student的時(shí)候,其classes屬性的值,將通過一個(gè)outter join連接查詢來獲取

·         或在Classes類的標(biāo)簽上設(shè)置fetch=”join”,當(dāng)我們load/get一個(gè)Classes類的實(shí)例的時(shí)候,其集合數(shù)據(jù),也是通過一個(gè)outter join連接查詢來抓取

·         查詢抓取(Select fetching - 另外發(fā)送一條 SELECT 語句抓取當(dāng)前對(duì)象的關(guān)聯(lián)實(shí)體或集合。除非你顯式的指定lazy="false"禁止 延遲抓取(lazy fetching),否則只有當(dāng)你真正訪問關(guān)聯(lián)關(guān)系的時(shí)候,才會(huì)執(zhí)行第二條select語句。 這種抓取策略,設(shè)置方法為:fetch=”select”

·         如在set標(biāo)簽上設(shè)置fetch=”select”,下面的查詢List list = session.createQuery("from Classes cls where id in (1,22)").list();將產(chǎn)生如下結(jié)果:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)

 

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?

 

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?

可見,總共發(fā)出:第一,查詢Classes的數(shù)據(jù);第二,因?yàn)椴樵兘Y(jié)果集中有兩個(gè)Classes對(duì)象,所以針對(duì)每個(gè)對(duì)象,都發(fā)出了一個(gè)查詢語句以便查詢其students集合的數(shù)據(jù)。

·          

·         子查詢抓取(Subselect fetching - 另外發(fā)送一條SELECT 語句抓取在前面查詢到(或者抓取到)的所有實(shí)體對(duì)象的關(guān)聯(lián)集合。除非你顯式的指定lazy="false" 禁止延遲抓取(lazy fetching),否則只有當(dāng)你真正訪問關(guān)聯(lián)關(guān)系的時(shí)候,才會(huì)執(zhí)行第二條select語句。 設(shè)置方法是:fetch=”subselect”,它只能被設(shè)置在集合映射的屬性上。

·         如在set標(biāo)簽上設(shè)置fetch=”sebselect”,下面的查詢List list = session.createQuery("from Classes cls where id in (1,22)").list();list對(duì)象中,將包含兩個(gè)Classes對(duì)象的實(shí)例,假設(shè)其集合上配置lazy=”false”,我們立刻就能看到hibernatesubselect抓取策略是:

以下是hibernate生成的SQL語句:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)



------君臨天下,舍我其誰------