天天看點

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 内尋找對應的資料,如果沒找到,再去資料庫中檢索。