可選值:
- org.hibernate.cache.HashtableCacheProvide
- org.hibernate.cache.EhCacheProvider
- org.hibernate.cache.OSCacheProvider
- org.hibernate.cache.SwarmCacheProvider
- org.hibernate.cache.TreeCacheProvider...
例如:
(1).hibernate.cfg.xml
- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
- <property name="hibernate.cache.use_second_level_cache">true</property>
(2)spring
- <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
- <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支持事務型緩存.
各種緩存實現
- hibernate.cache.use_minimal_puts:是否優化二級緩存來最小化讀寫操作,集羣時的緩存優化。可選值:true(默認):啓用最小化讀寫操作。false:禁用最小化讀寫操作。
- hibernate.cache.use_query_cache:是否緩存查詢結果(條件查詢時用)。可選值:true:緩存查詢結果。false:不緩存查詢結果
- hibernate.cache.use_second_level_cache:否啓用二級緩存。可選值:true:啓用二級緩存。false:不使用二級緩存。
- hibernate.cache.query_cache_factory:設置自定義的查詢緩存類全名,緩存類必須實現org.hibernate.cache.QueryCache接口。可選值:(1)org.hibernate.cache.StandardQueryCache(默認)。(2)自定義緩存實現類。
- hibernate.cache.region_prefix:二級緩存的前綴名稱。
- hibernate.cache.use_structured_entries:是否使用結構化的方式緩存對象。可選值:true:結構化方式緩存對象。false:不使用結構化的方式緩存對象。
附:echcache.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <ehcache>
- <diskStore path="java.io.tmpdir"/>
- <defaultCache
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="120"
- timeToLiveSeconds="120"
- overflowToDisk="true"/>
- <cache name="org.hibernate.cache.StandardQueryCache"
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="200"
- timeToLiveSeconds="500"
- overflowToDisk="true"/>
- <cache name ="org.hibernate.cache.UpdateTimestampsCache"
- maxElementsInMemory ="5000"
- eternal ="true"
- overflowToDisk ="true"/>
- </ehcache>
- maxElementsInMemory屬性用於指定緩存中最多可放多少個對象。
- eternal屬性指定緩存是否永久有效。
- timeToIdleSeconds屬性指定緩存閒置多久未被使用便清理掉。
- timeToLiveSeconds屬性指定緩存的生命長度。
- diskPersistent屬性指定緩存是否被持久化到硬盤中,保存路徑由<diskStore>標籤指定。
測試時,log4j.properties
- log4j.logger.org.hibernate=warn
- 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參數,可參考如下配置。
- <hibernate-configuration>
- <session-factory>
- .........
- <property name=” hibernate.jdbc.batch_size”>50</property>
- .........
- <session-factory>
- <hibernate-configuration>
配置hibernate.jdbc.batch_size參數的原因就是儘量少讀數據庫,hibernate.jdbc.batch_size參數值越大,讀數據庫的次數越少,速度越快。從上面的配置可以看出,Hibernate是等到程序積累到了50個SQL之後再批量提交。
hibernate.jdbc.batch_size參數值也可能不是設置得越大越好,從性能角度上講還有待商榷。這要考慮實際情況,酌情設置,一般情形設置30、50就可以滿足需求了。
- Session session=HibernateUtil.currentSession();
- Transatcion tx=session.beginTransaction();
- for(int i=0;i<10000;i++)
- ...{
- Student st=new Student();
- st.setName(“feifei”);
- session.save(st);
- if(i%50==0) //以每50個數據作爲一個處理單元
- ...{
- session.flush(); //保持與數據庫數據的同步
- session.clear(); //清除內部緩存的全部數據,及時釋放出佔用的內存
- }
- }
- tx.commit();
- .........
在一定的數據規模下,這種做法可以把系統內存資源維持在一個相對穩定的範圍。
注意:前面提到二級緩存,在這裏有必要再提一下。如果啓用了二級緩存,從機制上講Hibernate爲了維護二級緩存,我們在做插入、更新、刪除操作時,Hibernate都會往二級緩存充入相應的數據。性能上就會有很大損失,所以建議在批處理情況下禁用二級緩存。