Hibernate高級應用:性能優化策略

1.一級緩存(session裏面的實體對象,存放在內存中)

get/load/list/iterate可以將對象放入到一級緩存中

List操作不會利用一級緩存

get/load/iterate可以利用一級緩存

flush方法將改變後的同對象持久化到數據庫中

2.二級緩存

SessionFactory級別的緩存。默認的情況下是打開的。這是一個全局緩存策略。它可以對對象的數據進行全局緩存

一級緩存  二級緩存 緩存的是實體對象

緩存的keyID,緩存的value是實體對象

3.查詢緩存(慎用)

即對查詢的結果集進行緩存處理,以便下次相同條件相同HQL的情況下可以直接從緩存中獲取數據。

查詢緩存的作用,是對list操作的查詢結果集進行緩存!

緩存的是普通結果集

緩存的keyHQL中的語句與參數,緩存的value則:

(1)如果查詢的結果爲普通結果集,則緩存這些結果集

(2)如果查詢的結果爲實體對象,則緩存實體對象的ID列表

用查詢緩存的時候,二級緩存也要啓用,防止發出多條語句

我們使用list操作的時候,如果啓用了查詢緩存hibernate將根據當前查詢的HQL語句(及其參數值)計算出一個緩存的key值;查詢結果集,將作爲緩存的value值(但如果查詢結果集是一個對象結果集的話,其緩存的value值是對象的ID集合,而不是對象集合本身)。

<o:p> </o:p>

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

<property name="hibernate.cache.use_query_cache">true</property><o:p></o:p>

以便打開查詢緩存。

<o:p> </o:p>

查詢緩存,對對象查詢,將緩存其ID列表;對普通查詢,將緩存整個數據集合。所以,對於對象查詢,需要配合二級緩存來使用。

<o:p> </o:p>

在打開了查詢緩存之後,需要注意,調用query.list()操作之前,必須顯式調用query.setCachable(true)來標識某個查詢使用緩存。

4.批量抓取

(1)抓取策略,有一個對象 ,即如何獲取關聯的策略。

(2)什麼叫批量抓取:有一批對象,想得到這批對對象的關聯

3)在many-to-one/one-to-many中設置:fetch(在hbm.xml語句中配置)

Fetch="select" 查詢抓取,通過第二條語句查詢關聯(這是默認值)

Fetch="join"  連接抓取,在加載的同時通過一條外連接已經把關聯的對象加載

上來了,所以設置的lazy配置失效

Fetch="join"  對於批量抓取的時候是無效的

Fetch="select"可以定義批量抓取策略,在對方的class映射文件中配置batch-size

即可

 連接抓取(Join fetching - Hibernate通過 在SELECT語句使用OUTER JOIN(外連接)來 獲得對象的關聯實例或者關聯集合。 連接抓取策略可以被定義在<many-to-one/>或集合(如<set/>)標籤上。這種抓取策略,對load/get操作有效。

·         如在Student<many-to-one/>標籤上設置fetch=”join”,當我們load/get一個Student的時候,其classes屬性的值,將通過一個outter join連接查詢來獲取

·         或在Classes類的<set />標籤上設置fetch=”join”,當我們load/get一個Classes類的實例的時候,其集合數據,也是通過一個outter join連接查詢來抓取

·        查詢抓取(Select fetching - 另外發送一條 SELECT 語句抓取當前對象的關聯實體或集合。除非你顯式的指定lazy="false"禁止 延遲抓取(lazy fetching),否則只有當你真正訪問關聯關係的時候,纔會執行第二條select語句。 這種抓取策略,設置方法爲:fetch=”select”

·         如在set標籤上設置fetch=”select”,下面的查詢List list = session.createQuery("from Classes cls where id in (1,22)").list();將產生如下結果:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>

<o:p> </o:p>

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=?<o:p></o:p>

<o:p> </o:p>

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=?<o:p></o:p>

可見,總共發出:第一,查詢Classes的數據;第二,因爲查詢結果集中有兩個Classes對象,所以針對每個對象,都發出了一個查詢語句以便查詢其students集合的數據。<o:p></o:p>

·       <o:p> </o:p>

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

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

以下是hibernate生成的SQL語句:<o:p></o:p>

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>

<o:p> </o:p>

悲觀鎖和樂觀鎖

兩個人同時修改用一條數據時,就會才產生數據不一致

這是我們需要用樂觀鎖來解決這個問題!

悲觀鎖:鎖定一條記錄,當修改成功後,對方纔能修改(一直等待)

在實體bean中設置

Person p=(Person)session.get(Person.class, 1,LockOptions.UPGRADE);

缺點:當遇到多個線程的時候,會發送死鎖,效率也不高(不建議使用)

樂觀鎖(建議使用):通過版本號約束hibernate是否更新,避免了數據更新的丟失,在實體類中加屬性版本號:int versionNumber ,在對應的映射文件中添加<version name="versionNumber"></version>

5.批量更新/保存

向數據庫中插入1萬條數據,如何提高效率?

對於在Mysql數據庫中加入<property name="hibernate.connection.url">(oracle數據庫中則不需要加入)

jdbc:mysql://localhost/hibernate?rewriteBatchedStatements=true</property>

//<property name="hibernate.jdbc.batch_size">25</property>

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章