EHCache是一個純java實作的,目前來講使用最為廣泛的java緩存庫。它有着強大(分布式和memory、db等緩存政策)、輕巧(2.2.3版本有着<1mb的jar體積),使用簡單等特色,深受大家廣大開發者的喜愛。
本文将簡單介紹EHCache的一些使用配置。之後可能會另開一篇用以介紹EHCache與其他緩存産品的對比。
EHcache的配置
我們一般使用ehcache.xml作為EHCache的配置檔案,當然,檔案名可以任意的。
簡單使用EHCache
上面說了,EHCache是一個程序内的緩存類庫(貌似沒說。。。),那麼我們可以在任何情況下使用EHCache。 EHCache有着合理的預設值,是以我們甚至可以不用任何配置檔案就使用EHCache:
package org.xiaom.ehchache.action;
import java.util.Date;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
public class TestAction {
public static void main(String[] args) {
//建立CacheManager,開啟事務
CacheManager cm=CacheManager.create();
cm.getTransactionController().begin();
//添加Cache
cm.addCache("test_cache");
//擷取添加的Cache,添加元素
Cache cache=cm.getCache("test_cache");
cache.put(new Element("key", new Date()));
//送出事務
cm.getTransactionController().commit();
//使用緩存
Element element=cache.get("key");
System.out.println(element.getObjectValue());
}
}
從上面的代碼可以看到,單純使用EHCache是很簡單的。但WEB開發不是像上面的這樣過家家般簡單,事實上,凡是用到緩存的應用大都資料量和通路量較大,是以,我們應該挖EHCache的更多的功能。
在Web應用中使用EHCache
在把這個标題展開來說之前,我們需要明确幾個事情:
- 對于那些需要頻繁更改資料的表,使用的EHCache意義不大。因為如果程式更改了表中的内容,EHCache還需要将表中内容重新裝入緩存,并且抛棄舊的内容,如此開銷下來,緩存的意義也就不大了。
- 那些實時性要求很敏感的資料(賬戶餘額,實時排名等)也不适合采用緩存。當然,我們可以通過程式邏輯上保持緩存和庫的同步,但是一旦到了叢集環境中,這個問題就會變得很棘手。當然,這條論斷主觀性很強,螢幕前的你需要帶着批判性的眼光去審視我的這個言論。盲目的聽信他人等于迷失自己。雖然我真沒什麼好東西可以被聽信的。
到這兒,我們把這個标題中的内容分為兩部:
- 使用EHCache為資料提供緩存(整合Hibernate)
- 緩存常用頁面
EHCache當做Hibernate的二級緩存
上面的例子展示EHCache為資料提供緩存的操作(能力),我們知道,web應用裡面有些表是需要被頻繁地讀取和寫入(在同一個事務内)的,為此,ORM架構Hibernate提供了在Session之外的二級緩存,而我們今天所看的EHCache恰恰可以做為Hibernate二級緩存的提供者(事實上,絕大部分Hibernate應用都使用了EHCache作為二級緩存内容提供者,而且EHCache也成為了Hibernate的預設緩存)。同樣地,在Hibernate中使用和配置二級緩存也是很簡單便捷的:
我在SSH環境中的SessionFactory配置
<!-- Hibernate的SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
hibernate.show_sql=true
hibernate.format_sql=false
hibernate.query.substitutions=true 1, false 0
<!-- 啟用查詢緩存 -->
hibernate.cache.use_query_cache=true
<!-- 啟用二級緩存 -->
hibernate.cache.use_second_level_cache=true
<!-- 指定緩存提供者為EHCache -->
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
</value>
</property>
<property name="mappingLocations">
<list>
<value>classpath*:/org/xiaom/butler/bean/*.hbm.xml</value>
</list>
</property>
</bean>
為了便于管理EHCache的配置,我們在classpath(可以是src檔案夾)下建立一個ehcache.xml檔案:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 指定一個檔案目錄,當EHCache把資料寫到硬碟上時,将把資料寫到這個檔案目錄下 -->
<diskStore path="F:/test" />
<!--
帶*的為必選:
*name: 緩存名稱,必須唯一
*maxElementsInMemory:緩存在記憶體中的元素的最大數目
*maxElementsOnDisk:緩存在磁盤中的元素的最大數目
*overlowToDisk:記憶體中元素到達最大數目後是否将其寫入到diskStore所指定的位置
timeToIdleSeconds:元素可以空閑(未被命中)的最存在長時間(秒),0(預設值)為永久存在
timeToLiveSeconds:元素可以在記憶體中存活的最長時間(秒),0(預設值)為永久存在
*eternal:元素是否永久有效,如果ture,則忽略timeToIdleSeconds、timeToLiveSeconds
兩個設定,進而永久駐留記憶體
diskPersistent:重新開機jvm時是否将記憶體中元素寫入磁盤
diskExpiryThreadIntervalSeconds:此盤緩存失效檢查線程運作間隔
diskSpoolBufferSizeMB:EHCache為每一個Cache配置設定一個緩沖區,設定該緩沖區的大小
memoryStoreEvictionPolicy:淘汰元素時的算法:
LFU:最少使用的元素被淘汰
LRU:最近的、最少使用的元素被淘汰
FIFO:先進先出
-->
<cache name="org.xiaom.butler.user_cache" maxElementsInMemory="1000" eternal="true"
overflowToDisk="true" diskPersistent="true" maxElementsOnDisk="100000"/>
<!-- 預設緩存,如果找不到其他緩存就是使用預設緩存 -->
<defaultCache maxElementsInMemory="10000" eternal="false"
overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120" />
</ehcache>
除此之外,我們僅需要在bean.hbm.xml上配置緩存類型(<cache usage="read-write"/>),并指明緩存名稱即可:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.xiaom.butler.bean" default-lazy="false">
<class name="User" table="user" >
<cache usage="read-write" region="org.xiaom.butler.user_cache" />
<id name="id" type="integer" > <generator class="identity"></generator></id>
。。。。。
</class>
</hibernate-mapping>
關于更多緩存類型的資料,我們可以參考Hibernate的官方文檔或Google之。
有了上面的配置,我們就可以在dao層代碼中使用緩存了:
@Repository
public class TestDao extends BaseDao<Hotel, Integer>{
public User testCache(Integer id){
User u=null;
Session session=getSessionFactory().openSession();
session.get(User.class,id);//基于ID的查詢。
session.createCriteria(User.class).<span style="color:#ff0000;">setCacheable</span>(true).list();//查詢緩存,記得設定Cacheable哦
return u;
}
}
至此,EHCache作為Hibernate二級緩存提供者的配置已經完成,我們該如何驗證呢?
- 開啟hibernate.show_sql=true,觀察使用了緩存後的sql語句列印情況。如果沒有列印sql,很顯然就是資料讀取自緩存
- 開啟log4j.logger.org.hibernate.cache=debug,觀察日志記錄(我沒開啟過)
使用EHCache緩存常用頁面
細細講來,緩存某個頁面其實是個很大的問題,我們思考的地方其實有很多,例如一個電子商務網站的首頁要做緩存,我們最起碼應該滿足如下兩個要求:
- 商品根據運維系統的資料要精确顯示(定時更新頁面)
- 根據使用者喜好針對性顯示(頁面拆分後緩存)
- 。。。
是以這裡我僅給出一個簡單的執行個體(使用預設緩存來對index.jsp進行緩存),用以作為頁面緩存的入門級參考:
<!-- 讓EHCache的頁面緩存Filter去過濾特定頁面請求 -->
<filter>
<filter-name>page_cache</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<!-- index.jsp被緩存 -->
<filter-mapping>
<filter-name>page_cache</filter-name>
<url-pattern>index.jsp</url-pattern>
</filter-mapping>
有了以上的配置,接下來你可以自行驗證緩存是否生效。
分布式環境中使用EHCache
EHCache是支援分布式方式工作的,支援RMI,JGroups,JMS三種工作方式。其配置這裡就暫時不介紹了。 你可以下載下傳我的這份DEMO。但是我不是很推薦這樣做,主要是因為 EHCache的使用真的很簡單。
任何需要積分的下載下傳都是耍流氓