Hibernate學習:Hibernate的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中移除物件。如下:
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的配置檔案中設定如下:
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>