天天看點

EHCachey應用

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還需要将表中内容重新裝入緩存,并且抛棄舊的内容,如此開銷下來,緩存的意義也就不大了。
  • 那些實時性要求很敏感的資料(賬戶餘額,實時排名等)也不适合采用緩存。當然,我們可以通過程式邏輯上保持緩存和庫的同步,但是一旦到了叢集環境中,這個問題就會變得很棘手。當然,這條論斷主觀性很強,螢幕前的你需要帶着批判性的眼光去審視我的這個言論。盲目的聽信他人等于迷失自己。雖然我真沒什麼好東西可以被聽信的。

到這兒,我們把這個标題中的内容分為兩部:

  1. 使用EHCache為資料提供緩存(整合Hibernate)
  2. 緩存常用頁面

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二級緩存提供者的配置已經完成,我們該如何驗證呢?

  1. 開啟hibernate.show_sql=true,觀察使用了緩存後的sql語句列印情況。如果沒有列印sql,很顯然就是資料讀取自緩存
  2. 開啟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的使用真的很簡單。

任何需要積分的下載下傳都是耍流氓

繼續閱讀