1. 程式人生 > >Hibernate學習:Hibernate的cache管理

Hibernate學習:Hibernate的cache管理

Cache就是快取,它往往是提高系統性能的最重要手段,對資料起到一個蓄水池和緩衝的作用。Cache對於大量依賴資料讀取操作的系統而言尤其重要。在大併發量的情況下,如果每次程式都需要向資料庫直接做查詢操作,它們所帶來的效能開銷是顯而易見的,頻繁的網路輿,資料庫磁碟的讀寫操作都會大大降低系統的效能。此時如果能讓資料庫在本地記憶體中保留一個映象,下次訪問的時候只需要從記憶體中直接獲取,那麼顯然可以帶來不小的效能提升。引入Cache機制的難點是如何保證記憶體中資料的有效性,否則髒資料的出現將會給系統帶來難以預知的嚴重後果。雖然一個設計得很好的應用程式不用Cache也可以表現出讓人接受的效能,但毫無疑問,一些對讀取操作要求比較高的應用程式可以通過Cache獲得更高的效能。對於應用程式,Cache通過記憶體或磁碟儲存了資料庫中的當前有關資料狀態,它是一個儲存在本地的資料備份。Cache位於資料庫和應用程式之間,從資料庫更新資料,並給程式提供資料。
Hibernate實現了良好的Cache機制,可以藉助Hibernate內部的Cache迅速提高系統的資料讀取效能。Hibernate中的Cache可分為兩層:一級Cache和二級Cache。
一級Cache:
Session實現了第一級Cache,它屬於事務級資料緩衝。一旦事務結束,這個Cache也隨之失效。一個Session的生命週期對應一個數據庫事務或一個程式事務。
Session-cache保證了一個Session中兩次請求同一個物件時,取得的物件是同一個JAVA例項,有時它可以避免不必要的資料衝突。另外,它還能為另一些重要的效能提供保證:
1:在對一個物件進行自我迴圈引用時, 不至於產生堆疊溢位。

2:當資料庫事務結束時,對於同一個資料庫行,不會產生資料衝突,因為對於資料庫中的一行,最多隻有一個物件來表示它。
3:一個事務中可能會有很多個處理單元,在每一個處理單元中做的操作都會立即被另外的處理單元得知。
我們不用刻意去開啟Session-cache,它總是被開啟並且不能被關閉。當使用save(),update()或saveOrUpdate()來儲存資料更改,或通過load(),find(),list()等方法來得到物件時,物件就會被加入到Session-cache。
如果要同步很多資料物件,就需要有效地管理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快取了新加入的所有物件。記憶體溢位。要解決這全問題就需要把JDBC批處理數量設定為一個合理的數值(一般是10~20)。在Hibernate的配置檔案中可以加入以下屬性
<property name="hibernate.jdbc.batch_size"> 20 </property>
然後我們在程式中一定時刻就提交併更新Session的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,釋放記憶體
    }

}

tx.commit();
session.close();

二級Cache
二級Cache是SessionFactory範圍內的快取,所有的Session共享同一個二級Cache。在二級Cache中儲存永續性例項的散裝形式的資料。二級Cache的內部如何實現並不重要,重要的是採用哪種正確的快取策略,以及採用哪個Cache提供器。持久化不同的資料需要不同的Cache策略,比如一些因素將影響到Cache策略的選擇:資料的讀/寫比例,資料表是否能被其他的應用程式揚訪問等。對於一些讀/寫比例高的資料可以開啟它的快取,允許這些資料進入二級快取容器有利於系統性能的優化;而對於能被其它應用程式訪問的資料物件,最好將此物件的二級Cache選項關閉。
設定Hibernate的二級Cache需要分兩步進行:首先確認使用什麼資料併發策略,然後配置快取過期時間並設定Cache提供器。
有4種內建的Hibernate資料併發衝突策略,代表資料庫隔離級別,如下:
1:事務(Transaction)僅在受管理的環境中可用。它保證可重讀的事務隔離級別,可以對讀/寫比例高,很少更新的資料採用該策略。
2:讀寫(read-write)使用時間戳機制維護讀寫提交事務隔離級別。可以對讀/寫比例高,很少更新的資料採用該策略。
3:非嚴格讀寫(notstrict-read-write)不保證Cache和資料庫之間的資料庫的一致性。使用此策略時,應該設定足夠的快取過期時間,否則可能從快取中讀出髒資料。當一些資料極少改變,並且當這些資料和資料庫有一部份不量影響不大時,可以使用此策略。
4:只讀(read-only)當確保資料永不改變時,可以使用此策略。

我們確定了Cache策略後,就要挑選一個高效的Cache提供器,它將作為外掛被Hibernate呼叫。Hibernate允許使用下述幾種快取外掛:
EhCache:可以在JVM中作為一個簡單程序範圍內的快取,它可以把快取的資料放入記憶體或磁碟,並支援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> EhCacheProvider類是位於Hibernate3.jar包中而不是ehcache-1.1.jar包中。EhCache有自己的配置文件,名為chcache.xml。Hibernate3.x中的etc目錄下有ehcache.xml的示例檔案,只須要將 它COPY到我們的應用程式src目錄下(編譯時會把ehcache.xmlCOPY到WEB-INF/classes目錄下)。對其中的相關值進行更改以和自己的程式相適應。進行配置後,在ehcache.xml檔案中的程式碼如下: <ehcache>
    <diskStore path="c:\\cache"/>    //設定cache.data檔案存放位置

    <defaultCache
                
maxElementsInMemory="10000" //快取中允許建立的最大物件數
                eternal
="false"    //快取中物件是否為永久的
                timeToIdleSeconds
="120"//快取資料鈍化時間(即物件在它過期前的空閒時間)
                timeToLiveSeconds
="120"//快取資料生存時間(即物件在它過期前的生存時間)
                overflowToDisk
="true"
    
/>
    
    <cache name="Student"    //使用者自定義的Cache配置
                 maxElementsInMemory
="10000"
                 eternal
="false"
                 timeToIdleSeconds
="300"
                 timeToLiveSeconds
="600"
                 overflowToDisk
="true"
                 
/>
</ehcache> 此外我們還需要在持久化類的對映檔案中進行配置。例如,Group(班級)和Student(學生)是一對多的關係,它們對應的資料表分別是t_group和t_student。現在要把Student類的資料進行二級快取,這需要在二個對映檔案中都對二級快取進行配置。
在Group.hbm.xml中如下
在其<set></set>中新增 <cache usage="read-write"/><!--集合中的資料被快取--> 上述檔案雖然在<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>