2010年6月10日

[轉貼記錄] hibernate學習筆記

原创 hibernate學習筆記:hibernate中的Cache管理 收藏

Hibernate 中實現了良好的Cache 機制,我們可以借助Hibernate 內部的Cache迅速提高系統數據讀取性能。

需要注意的是:Hibernate做為一個應用級的數據訪問層封裝,只能在其作用範圍內保持 Cache中數據的的有效性,也就是說,在我們的系統與第三方系統共享數據庫的情況下,Hibernate的Cache機制可能失效。一個很簡單的例子, 如果你用access修改了庫中的值,那麼這就不會更新JVM中的緩衝池,這就導致了贓數據的產生。

Hibernate 在本地JVM 中維護了一個緩衝池,並將從數據庫獲得的數據保存到池中以供下次重複使用(如果在Hibernate中數據發生了變動,Hibernate同樣也會更新池 中的數據版本)。此時,如果有第三方系統對數據庫進行了更改,那麼,Hibernate並不知道數據庫中的數據已經發生了變化,也就是說,池中的數據還是 修改之前的版本,下次讀取時,Hibernate會將此數據返回給上層代碼,從而導致潛在的問題。外部系統的定義,並非限於本系統之外的第三方系統,即使 在本系統中,如果出現了繞過Hibernate數據存儲機制的其他數據存取手段,那麼Cache的有效性也必須細加考量。如,在同一套系統中,基於 Hibernate和基於JDBC的兩種數據訪問方式並存,那麼通過JDBC更新數據庫的時候,Hibernate同樣無法獲知數據更新的情況,從而導致 髒數據的出現。

基於Java 的Cache 實現,最簡單的莫過於HashTable,hibernate 提供了基於Hashtable 的Cache 實現機制,不過,由於其性能和功能上的侷限,僅供開發調試中使用。同時,Hibernate 還提供了面向第三方Cache 實現的接口,如JCS、EHCache、OSCache、JBoss Cache、SwarmCache等。

Hibernate中的 Cache大致分為兩層,第一層Cache在Session實現,屬於事務級數據緩衝,一旦事務結束,這個Cache 也就失效。此層Cache 為內置實現,無需我們進行干涉。第二層Cache,是Hibernate 中對其實例範圍內的數據進行緩存的管理容器。

我們主要學習第二層 Cache。

Hibernate早期版本中採用了JCS(Java Caching System -Apache Turbine項目中的一個子項目)作為默認的第二層Cache實現。由於JCS的發展停頓,以及其內在的一些問題(在某些情況下,可能導致內存洩漏以及 死鎖),新版本的Hibernate已經將JCS去除,並用EHCache作為其默認的第二級Cache實現。相對JCS,EHCache更加穩定,並具 備更好的緩存調度性能,缺陷是目前還無法做到分佈式緩存,如果我們的系統需要在多台設備上部署,並共享同一個數據庫,必須使用支持分佈式緩存的Cache 實現(如JCS、JBossCache)以避免出現不同系統實例之間緩存不一致而導致髒數據的情況。Hibernate對Cache進行了良好封裝,透明 化的Cache機制使得我們在上層結構的實現中無需面對繁瑣的Cache維護細節。

目前Hibernate支持的Cache實現有:

HashTable:net.sf.hibernate.cache.HashtableCacheProvider 支持查詢緩衝。

EHCache:net.sf.ehcache.hibernate.Provider 支持查詢緩衝。

OSCache:net.sf.hibernate.cache.OSCacheProvider 支持查詢緩衝。

SwarmCache:net.sf.hibernate.cache.SwarmCacheProvider 支持集群。

JBossCache:net.sf.hibernate.cache.TreeCacheProvider 支持集群。

其 中SwarmCache 提供的是invalidation 方式的分佈式緩存,即當集群中的某個節點更新了緩存中的數據,即通知集群中的其他節點將此數據廢除,之後各個節點需要用到這個數據的時候,會重新從數據庫 中讀入並填充到緩存中。而JBossCache提供的是Reapplication式的緩衝,即如果集群中某個節點的數據發生改變,此節點會將發生改變的 數據的最新版本複製到集群中的每個節點中以保持所有節點狀態一致。

使用第二層Cache,需要在hibernate的配置文件進行配置(省 略)主要介紹一下cache策略

cache策略可選值有以下幾種:

1. read-only 只讀。
2. read-write 可讀可寫。
3. nonstrict-read-write 如果程序對並發數據修改要求不是非常嚴格,只是偶爾需要更新數據,可以採用本選項,以減少無謂的檢查,獲得較好的性能。
4. transactional 事務性cache。在事務性Cache 中,Cache 的相關操作也被添加到事務之中,如果由於某種原因導致事務失敗,我們可以連同緩衝池中的數據一同回滾到事務開始之前的狀態。目前Hibernate 內置的Cache 中,只有JBossCache 支持事務性的Cache實現。

其他參數簡介:

maxElementsInMemory="10000" //Cache中最大允許保存的數據數量
eternal="false" //Cache中數據是否為常量
timeToIdleSeconds="120" //緩存數據鈍化時間
timeToLiveSeconds="120" //緩存數據的生存時間
overflowToDisk="true" //內存不足時,是否啟 用磁盤緩存

需要注意的是Hibernate 的數據庫查詢機制。我們從查詢結果中取出數據的時候,用的最多的是兩個方法:Query.list();Query.iterate();

對 於list方法而言,實際上Hibernate是通過一條Select SQL獲取所有的記錄。並將其讀出,填入到POJO中返回。

而iterate 方法,則是首先通過一條Select SQL 獲取所有符合查詢條件的記錄的id,再對這個id 集合進行循環操作,通過單獨的Select SQL 取出每個id 所對應的記錄,之後填入POJO中返回。

也就是說,對於list 操作,需要一條SQL 完成。而對於iterate 操作,需要n+1條SQL。

看上去iterate方法似乎有些多餘,但在不同的情況下確依然有其獨特的功效,如對海量數據的查詢,如果用 list方法將結果集一次取出,內存的開銷可能無法承受。另一方面,對於我們現在的Cache機制而言,list方法將不會從Cache中讀取數據,它總 是一次性從數據庫中直接讀出所有符合條件的記錄。而iterate 方法因為每次根據id獲取數據,這樣的實現機制也就為從Cache讀取數據提供了可能,hibernate首先會根據這個id 在本地Cache 內尋找對應的數據,如果沒找到,再去數據庫中檢索。

沒有留言: