Hibernate緩存配置/批量處理

   Hibernate除了自動對Session級別的事務進行一級緩存外,二級緩存都需要實現org.hibernate.cache.CacheProvider接口,Hibernate已經實現了一些緩存,開發人員可以直接配置使用,同時要啓用二級緩存,配置hibernate.cache.use_second_level_cache爲true。

可選值:
  1. org.hibernate.cache.HashtableCacheProvide
  2. org.hibernate.cache.EhCacheProvider
  3. org.hibernate.cache.OSCacheProvider
  4. org.hibernate.cache.SwarmCacheProvider
  5. org.hibernate.cache.TreeCacheProvider...

例如:
(1).hibernate.cfg.xml
Xml代碼  收藏代碼
  1. <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
  2. <property name="hibernate.cache.use_second_level_cache">true</property>   

(2)spring
Xml代碼  收藏代碼
  1. <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>  
  2. <prop key="hibernate.cache.use_second_level_cache">true</prop>   


   Hibernate在默認情況下並不會對所有實體對象進行緩存,所以,我們需要指定緩存哪些對象,在實體對象的映射文件中(相應的<class>標籤內部),添加如下配置:
<cache usage="read-only"/> 或者在hibernate.cfg.xml中添加如下配置:
<class-cache class="com.xxx.hibernate.XXClass" usage="read-only"/>

usage="read-only"是“只讀”緩存策略。

注意,這個<cache>標籤只能放在<class>標籤的內部,而且必須處在<id>標籤的前面。

    Hibernate二級緩存是SessionFactory級的緩存,它允許多個Session間共享,使用時需要使用第三方的緩存組件,新版Hibernate將EHcache作爲默認的二級緩存實現.

    緩存同步策略:緩存同步策略決定了數據對象在緩存中的存取規則,我們必須爲每個實體類指定相應的緩存同步策略.Hibernate中提供了4種不同的緩存同步策略:
    1.read-only:只讀.對於不會發生改變的數據可使用.
    2.nonstrict-read-write:如果程序對併發訪問下的數據同步要求不嚴格,且數據更新頻率較低,採用本緩存同步策略可獲得較好性能.
    3.read-write:嚴格的讀寫緩存.基於時間戳判定機制,實現了"read committed"事務隔離等級.用於對數據同步要求的情況,但不支持分佈式緩存,實際應用中使用最多的緩存同步策略.
    4.transactional: 事務型緩存,必須運行在JTA事務環境中.此緩存中,緩存的相關操作被添加到事務中(此緩存類似於一個內存數據庫),如事務失敗,則緩衝池的數據會一同回 滾到事務的開始之前的狀態.事務型緩存實現了"Repeatable read"事務隔離等級,有效保證了數據的合法性,適應於對關鍵數據的緩存,Hibernate內置緩存中,只有JBossCache支持事務型緩存.

各種緩存實現
  1. hibernate.cache.use_minimal_puts:是否優化二級緩存來最小化讀寫操作,集羣時的緩存優化。可選值:true(默認):啓用最小化讀寫操作。false:禁用最小化讀寫操作。
  2. hibernate.cache.use_query_cache:是否緩存查詢結果(條件查詢時用)。可選值:true:緩存查詢結果。false:不緩存查詢結果
  3. hibernate.cache.use_second_level_cache:否啓用二級緩存。可選值:true:啓用二級緩存。false:不使用二級緩存。
  4. hibernate.cache.query_cache_factory:設置自定義的查詢緩存類全名,緩存類必須實現org.hibernate.cache.QueryCache接口。可選值:(1)org.hibernate.cache.StandardQueryCache(默認)。(2)自定義緩存實現類。
  5. hibernate.cache.region_prefix:二級緩存的前綴名稱。
  6. hibernate.cache.use_structured_entries:是否使用結構化的方式緩存對象。可選值:true:結構化方式緩存對象。false:不使用結構化的方式緩存對象。

附:echcache.xml
Xml代碼  收藏代碼
  1. <?xml version="1.0" encoding="UTF-8"?>     
  2. <ehcache>  
  3.     <diskStore path="java.io.tmpdir"/>  
  4.     <defaultCache  
  5.         maxElementsInMemory="10000"  
  6.         eternal="false"  
  7.         timeToIdleSeconds="120"  
  8.         timeToLiveSeconds="120"  
  9.         overflowToDisk="true"/>  
  10.           
  11.      <cache  name="org.hibernate.cache.StandardQueryCache"         
  12.           maxElementsInMemory="10000"         
  13.           eternal="false"         
  14.           timeToIdleSeconds="200"         
  15.           timeToLiveSeconds="500"         
  16.           overflowToDisk="true"/>  
  17.                
  18.      <cache name ="org.hibernate.cache.UpdateTimestampsCache"   
  19.          maxElementsInMemory ="5000"  
  20.          eternal ="true"   
  21.          overflowToDisk ="true"/>   
  22.        
  23. </ehcache>  

  • maxElementsInMemory屬性用於指定緩存中最多可放多少個對象。
  • eternal屬性指定緩存是否永久有效。
  • timeToIdleSeconds屬性指定緩存閒置多久未被使用便清理掉。
  • timeToLiveSeconds屬性指定緩存的生命長度。
  • diskPersistent屬性指定緩存是否被持久化到硬盤中,保存路徑由<diskStore>標籤指定。

測試時,log4j.properties
Java代碼  收藏代碼
  1. log4j.logger.org.hibernate=warn     
  2. log4j.logger.org.hibernate.cache=debug  


批量處理:
由於Hibernate對這兩種緩存有着不同的管理機制,對於二級緩存,我們可以對它的大小進行相關配置,而對於內部緩存,Hibernate就採取了“放任自流”的態度了,對它的容量並沒有限制。現在癥結找到了,我們做海量數據插入的時候,生成這麼多的對象就會被納入內部緩存(內部緩存是在內存中做緩存的),這樣你的系統內存就會一點一點的被蠶食,如果最後系統被擠“炸”了,也就在情理之中了。

    我們想想如何較好的處理這個問題呢?有的開發條件又必須使用Hibernate來處理,當然有的項目比較靈活,可以去尋求其他的方法。

   這裏推薦兩種方法:
   (1):優化Hibernate,程序上採用分段插入及時清除緩存的方法。
   (2):繞過Hibernate API ,直接通過 JDBC API 來做批量插入,這個方法性能上是最 好的,也是最快的。
    對於上述中的方法1,其基本是思路爲:優化Hibernate,在配置文件中設置hibernate.jdbc.batch_size參數,來指定每次提交SQL的數量;程序上採用分段插入及時清除緩存的方法(Session實現了異步write-behind,它允許Hibernate顯式地寫操作的批處理),也就是每插入一定量的數據後及時的把它們從內部緩存中清除掉,釋放佔用的內存。
     設置hibernate.jdbc.batch_size參數,可參考如下配置。
Xml代碼  收藏代碼
  1. <hibernate-configuration>  
  2. <session-factory>  
  3. .........  
  4. <property name=” hibernate.jdbc.batch_size”>50</property>  
  5. .........  
  6. <session-factory>  
  7. <hibernate-configuration>  


配置hibernate.jdbc.batch_size參數的原因就是儘量少讀數據庫,hibernate.jdbc.batch_size參數值越大,讀數據庫的次數越少,速度越快。從上面的配置可以看出,Hibernate是等到程序積累到了50個SQL之後再批量提交。

    hibernate.jdbc.batch_size參數值也可能不是設置得越大越好,從性能角度上講還有待商榷。這要考慮實際情況,酌情設置,一般情形設置30、50就可以滿足需求了。
Java代碼  收藏代碼
  1. Session session=HibernateUtil.currentSession();  
  2. Transatcion tx=session.beginTransaction();  
  3. for(int i=0;i<10000;i++)  
  4. ...{  
  5. Student st=new Student();  
  6. st.setName(“feifei”);  
  7. session.save(st);  
  8. if(i%50==0//以每50個數據作爲一個處理單元   
  9. ...{  
  10. session.flush(); //保持與數據庫數據的同步   
  11. session.clear(); //清除內部緩存的全部數據,及時釋放出佔用的內存   
  12. }  
  13. }  
  14. tx.commit();  
  15. .........  


在一定的數據規模下,這種做法可以把系統內存資源維持在一個相對穩定的範圍。

    注意:前面提到二級緩存,在這裏有必要再提一下。如果啓用了二級緩存,從機制上講Hibernate爲了維護二級緩存,我們在做插入、更新、刪除操作時,Hibernate都會往二級緩存充入相應的數據。性能上就會有很大損失,所以建議在批處理情況下禁用二級緩存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章