Hibernate中的Cache管理
Hibernate實現(xiàn)了良好的Cache機制,可以借助Hibernate內(nèi)部的Cache迅速提高系統(tǒng)的數(shù)據(jù)讀取性能。Hibernate中的Cache可分為兩層:一級Cache和二級Cache。
一級Cache:
Session實現(xiàn)了第一級Hibernate Cache,它屬于事務級數(shù)據(jù)緩沖。一旦事務結(jié)束,這個Cache也隨之失效。一個Session的生命周期對應一個數(shù)據(jù)庫事務或一個程序事務。
Session-cache保證了一個Session中兩次請求同一個對象時,取得的對象是同一個JAVA實例,有時它可以避免不必要的數(shù)據(jù)沖突。另外,它還能為另一些重要的性能提供保證:
1:在對一個對象進行自我循環(huán)引用時, 不至于產(chǎn)生堆棧溢出。
2:當數(shù)據(jù)庫事務結(jié)束時,對于同一個數(shù)據(jù)庫行,不會產(chǎn)生數(shù)據(jù)沖突,因為對于數(shù)據(jù)庫中的一行,最多只有一個對象來表示它。
3:一個事務中可能會有很多個處理單元,在每一個處理單元中做的操作都會立即被另外的處理單元得知。
我們不用刻意去打開Session-cache,它總是被打開并且不能被關閉。當使用save(),update()或saveOrUpdate()來保存數(shù)據(jù)更改,或通過load(),find(),list()等方法來得到對象時,對象就會被加入到Session-cache。
如果要同步很多數(shù)據(jù)對象,就需要有效地管理Cache,可以用Session的evict()方法從一級Cache中移除對象。如下:
- Session session = HibernateUtil.currentSession();
- Transaction tx = session.beginTransaction();
- for(int i = 0 ; i <100000 ; i++)
- {
- Student stu = new Student();
- session.save(stu);
- }
- tx.commit();
session.close();在保存50000個或更多對象時,程序可能會拋出OutOfMemoryException異常,因為Hibernate Cache在一級緩存了新加入的所有對象。內(nèi)存溢出。要解決這全問題就需要把JDBC批處理數(shù)量設置為一個合理的數(shù)值(一般是10~20)。在Hibernate Cache的配置文件中可以加入以下屬性
<property name="hibernate.jdbc.batch_size"> 20 </property>
然后我們在程序中一定時刻就提交并更新Session的Hibernate Cache:
- Session session = HibernateUtil.currentSession();
- Transaction tx = session.beginTransaction();
- for(int i = 0 ; i <100000 ; i++)
- {
- Student stu = new Student();
- session.save(stu);
- if(i%20 == 0) //每保存完20個對象后,進行如下操作
- {
- session.flush();//這個會提交更新
- session.clear();//清除Cache,釋放內(nèi)存
- }
- }
二級Cache
二級Cache是SessionFactory范圍內(nèi)的緩存,所有的Session共享同一個二級Cache。在二級Cache中保存持久性實例的散裝形式的數(shù)據(jù)。二級Cache的內(nèi)部如何實現(xiàn)并不重要,重要的是采用哪種正確的緩存策略,以及采用哪個Cache提供器。持久化不同的數(shù)據(jù)需要不同的Cache策略,比如一些因素將影響到Cache策略的選擇:數(shù)據(jù)的讀/寫比例,數(shù)據(jù)表是否能被其他的應用程序揚訪問等。對于一些讀/寫比例高的數(shù)據(jù)可以打開它的緩存,允許這些數(shù)據(jù)進入二級緩存容器有利于系統(tǒng)性能的優(yōu)化;而對于能被其它應用程序訪問的數(shù)據(jù)對象,最好將此對象的二級Cache選項關閉。
設置Hibernate Cache的二級需要分兩步進行:首先確認使用什么數(shù)據(jù)并發(fā)策略,然后配置緩存過期時間并設置Hibernate Cache提供器。
有4種內(nèi)置的Hibernate數(shù)據(jù)并發(fā)沖突策略,代表數(shù)據(jù)庫隔離級別,如下:
1:事務(Transaction)僅在受管理的環(huán)境中可用。它保證可重讀的事務隔離級別,可以對讀/寫比例高,很少更新的數(shù)據(jù)采用該策略。
2:讀寫(read-write)使用時間戳機制維護讀寫提交事務隔離級別。可以對讀/寫比例高,很少更新的數(shù)據(jù)采用該策略。
3:非嚴格讀寫(notstrict-read-write)不保證Cache和數(shù)據(jù)庫之間的數(shù)據(jù)庫的一致性。使用此策略時,應該設置足夠的緩存過期時間,否則可能從緩存中讀出臟數(shù)據(jù)。當一些數(shù)據(jù)極少改變,并且當這些數(shù)據(jù)和數(shù)據(jù)庫有一部份不量影響不大時,可以使用此策略。
4:只讀(read-only)當確保數(shù)據(jù)永不改變時,可以使用此策略。
我們確定了Hibernate Cache策略后,就要挑選一個高效的Cache提供器,它將作為插件被Hibernate調(diào)用。Hibernate允許使用下述幾種緩存插件:
EhCache:可以在JVM中作為一個簡單進程范圍內(nèi)的緩存,它可以把緩存的數(shù)據(jù)放入內(nèi)存或磁盤,并支持Hibernate中可選用的查詢緩存。
OpenSymphony OSCache:和EhCache相似,并且提供了豐富的緩存過期策略。
◆SwarmCache:可作為集群范圍的緩存,但不支持查詢緩存。
◆JBossCache:可作為集群范圍的緩沖,但不支持查詢緩存。
在Hibernate中使用EhCache
EhCache是一個純JAVA程序,可以在Hibernate中作為一個插件引入。在Hibernate中使用EhCache需要在Hibernate的配置文件中設置如下:
- <propery name="hibernate.cache.provider_class">
- org.hibernate.cache.EhCacheProvider
- </property>
- <ehcache>
- <diskStore path="c:\\cache"/> //設置cache.data文件存放位置
- <defaultCache
- maxElementsInMemory="10000" //緩存中允許創(chuàng)建的最大對象數(shù)
- eternal="false" //緩存中對象是否為永久的
- timeToIdleSeconds="120"//緩存數(shù)據(jù)鈍化時間(即對象在它過期前的空閑時間)
- timeToLiveSeconds="120"//緩存數(shù)據(jù)生存時間(即對象在它過期前的生存時間)
- overflowToDisk="true"
- />
- <cache name="Student" //用戶自定義的Cache配置
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="300"
- timeToLiveSeconds="600"
- overflowToDisk="true"
- />
- </ehcache>
此外我們還需要在持久化類的映射文件中進行配置。例如,Group(班級)和Student(學生)是一對多的關系,它們對應的數(shù)據(jù)表分別是t_group和t_student?,F(xiàn)在要把Student類的數(shù)據(jù)進行二級緩存,這需要在二個映射文件中都對二級緩存進行配置。
在Group.hbm.xml中如下,在其<set></set>中添加
<cache usage="read-write"/><!--集合中的數(shù)據(jù)被緩存-->上述文件雖然在<set>標記中設置了<cache usage="read-write"/>,但Hibernate只是把Group相關的Student的主鍵ID加入到緩存中,如果希望把整個Student的散裝屬性都加入到二級緩存中,還需要在Student.hbm.xml文件的<class>標記中添加<cache>子標記。如下:
- <class name="Student" table="t_student">
- <cache usage="read-write" /><!--cache標記需跟在class標記后-->
- </class>
【編輯推薦】