合理使用Ehcache

    Ehcache是来sourceforge(http://ehcache.sourceforge.net/)的开源项目,是纯Java实现的简单、快速的Cache组件。可以对页面、对象、数据进行缓存,支持集群/分布式缓存。

    如果整合Spring、Hibernate也非常的简单,Spring对Ehcache的支持也非常好。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度。

    使用S2SH开发网站,网站首页需要展示的数据多,访问量大。如果不做处理,则频繁的查询数据库,结果是页面显示的慢,服务器、数据库不堪重负。如果网站页面所展示的数据的更新不是特别频繁,想提高页面显示的速度,减轻服务器的负担,此时应该考虑使用缓存。

1.EhCache是什么
     EhCache是Hibernate的二级缓存技术之一,可以把查询出来的数据存储在内存或者磁盘,节省下次同样查询语句再次查询数据库,大幅减轻数据库压力;

2.EhCache的使用注意点
     当用Hibernate的方式修改表数据(save,update,delete等等),这时EhCache会自动把缓存中关于此表的所有缓存全部删除掉(这样能达到同步)。但对于数据经常修改的表来说,可能就失去缓存的意义了(不能减轻数据库压力);

3.EhCache使用的场合
     3.1比较少更新表数据
         EhCache一般要使用在比较少执行write操作的表(包括update,insert,delete等)[Hibernate的二级缓存也都是这样];
     3.2对并发要求不是很严格的情况
         两台机子中的缓存是不能实时同步的;
     3.3就S2SH来讲,做缓存有两种方式:
         1启用Hibernate的二级缓存。2使用页面缓存。
     3.4使用缓存有一个原则:
         越高层次的缓存效果越好。 推荐使用页面缓存。

4.EhCache概念了解(ehcache.xml解释)

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
	<diskStore path="java.io.tmpdir" />
	
	<defaultCache 
		maxElementsInMemory="500" 
		eternal="false" 
		timeToIdleSeconds="300" 
		timeToLiveSeconds="1200" 
		overflowToDisk="true" />
	
	<cache 
		name="testcache1" 
		maxElementsInMemory="150" 
		eternal="false" 
		timeToLiveSeconds="36000" 
		timeToIdleSeconds="3600" 
		overflowToDisk="true"/> 
</ehcache>

4.1 maxElementsInMemory
           如maxElementsInMemory="10000" ,内存中存储的对象的个数, 内存管理的缓存元素数量最大限值。 

     4.2 overflowToDisk
           如overflowToDisk="true" 对象在内存中达到最大个数的时候,是否写入硬盘。 

     4.3 eternal
           如eternal="false",表示cache中的对象是否过期,缺省为过期(按照配置中的时间),如果改为true,表示该对象永远不过期。 即cache中的元素将一直保存在内存中,不会因为时间超时而丢失,所以在这个值为true的时候,timeToIdleSeconds和timeToLiveSeconds两个属性的值就不起作用了。

     4.4 maxElementsOnDisk
          如maxElementsOnDisk="10000000" 在硬盘上最大的对象个数, 硬盘管理的缓存元素数量最大限值。默认值为0,就是没有限制。 

     4.5 timeToIdleSeconds
          如timeToIdleSeconds="3600" 设定元素在过期前空闲状态的时间,只对非持久性缓存对象有效。即多长时间不访问该缓存,那么ehcache就会清除该缓存。默认值为0,值为0意味着元素可以闲置至无限长时间。 

     4.6 timeToLiveSeconds
           如timeToLiveSeconds="100000" 设定元素从创建到过期的时间。对象存活多少秒过期. 默认值为0,值为0意味着元素可以存活至无限长时间。 意思是从cache中的某个元素从创建到消亡的时间,从创建开始计时,当超过这个时间,这个元素将被从cache中清除。

     4.7 diskPersistent 
           如diskPersistent="false" 是否持久化磁盘缓存,设定在虚拟机重启时是否进行磁盘存储,默认为false。要想把cache真正持久化到磁盘,写程序时必须注意,在是用net.sf.ehcache.Cache的void put (Element element)方法后要使用void flush()方法。

     4.8 diskExpiryThreadIntervalSeconds
           如diskExpiryThreadIntervalSeconds=”1000”: 访问磁盘线程活动时间。

     4.9 diskSpoolBufferSizeMB
           存入磁盘时的缓冲区大小,默认30MB,每个缓存都有自己的缓冲区。

     4.10 emoryStoreEvictionPolicy
           如 emoryStoreEvictionPolicy=” LRU”,元素逐出缓存规则。共有三种,(LRU)最近最少使用(缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存),为默认。First In First Out (FIFO),先进先出。Less Frequently Used(specified as LFU)最少使用(直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存)。

     4.11 name
           指定一个cache的名字,用来识别不同的cache,必须惟一。

其中必须要填的属性为:  maxElementsInMemory   maxElementsOnDisk   eternal   overflowToDisk

5.EhCache页面缓存应用
       
毫无疑问,几乎所有的网站的首页都是访问率最高的,而首页上的数据来源又是非常广泛的,大多数来自不同的对象,而且有可能来自不同的db,所以给首页做缓存是一个不错的主意,那么主页的缓存策略是什么样子的呢,我认为应该是某个固定时间之内不变的,比如说2分钟更新一次。

    那么这个缓存应该做在什么地方呢,让我们来看一下,假设您的应用的结构是page-filter-action-service-dao-db,这个过程中的-的地方都是可以做缓存的地方,根据页面缓存的特征,应该把页面缓存做到尽量靠近客户的地方,就是在page和filter之间,这样的优点就是第一个用户请求之后,页面被缓存,第二个用户再来请求的时候,走到filter这个请求就结束了,无需再走后面的action-service-dao-db。带来的好处是服务器压力的减低和客户段页面响应速度的加快。

接着我们来看一下SimplePageCachingFilter的配置,

<filter>

        <filter-name>indexCacheFilter<filter-name>

        <filter-class>

            net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter

        <filter-class>

<filter>

<filter-mapping>

        <filter-name>indexCacheFilter<filter-name>

        <url-pattern>*index.action<url-pattern>

<filter-mapping>

    就只需要这么多步骤,我们就可以给某个页面做一个缓存的,把上面这段配置放到你的web.xml中,那么当你打开首页的时候,你会发现,2分钟才会有一堆sql语句出现在控制台上。当然你也可以调成5分钟,总之一切都在控制中。

    好了,缓存整个页面看上去是非常的简单,甚至都不需要写一行代码,只需要几行配置就行了,够简单吧,虽然看上去简单,但是事实上内部实现却不简单哦,有兴趣的话,大家可以看看SimplePageCachingFilter继承体系的源代码。

    上面的配置针对的情况是缓存首页的全部,如果你只想缓存首页的部分内容时,你需要使用SimplePageFragmentCachingFilter这个filter。我们看一下如下片断:

<filter>

        <filter-name>indexCacheFilter<filter-name>

        <filter-class>

            net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter

       <filter-class>

<filter>
<filter-mapping>

        <filter-name>indexCacheFilter<filter-name>

        <url-pattern>*/index_right.jsp<url-pattern>

<filter-mapping>

这个jsp需要被jsp:include到其他页面,这样就做到的局部页面的缓存。这一点貌似没有oscache的tag好用。

    事实上在cachefilter中还有一个特性,就是gzip,也就是说缓存中的元素是被压缩过的,如果客户浏览器支持压缩的话,filter会直接返回压缩过的流,这样节省了带宽,把解压的工作交给了客户浏览器,如果客户的浏览器不支持gzip,那么filter会把缓存的元素拿出来解压后再返回给客户浏览器(大多数爬虫是不支持gzip的,所以filter也会解压后再返回流),这样做的优点是节省带宽,缺点就是增加了客户浏览器的负担(但是我觉得对当代的计算机而言,这个负担微乎其微)。

    好了,如果你的页面正好也需要用到页面缓存,不防可以考虑一下ehcache,因为它实在是非常简单,而且易用。

6.EhCache的API(缓存基本上以配置方式为主)
    
CacheManager主要的缓存管理类,一般一个应用为一个实例,如下
    CacheManager.create();

    也可以使用new CacheManager的方式创建
    默认的配置文件为ehcache.xml文件,也可以使用不同的配置:

    CacheManager manager = new CacheManager("src/config/other.xml");     

缓存的创建,采用自动的方式
CacheManager singletonManager = CacheManager.create();
singletonManager.addCache("testCache");
Cache test = singletonManager.getCache("testCache");     

或者直接创建Cache
CacheManager singletonManager = CacheManager.create();
Cache memoryOnlyCache = new Cache("testCache", 5000, false, false, 5, 2);
manager.addCache(memoryOnlyCache);
Cache test = singletonManager.getCache("testCache"); 

删除cache
CacheManager singletonManager = CacheManager.create();
singletonManager.removeCache("sampleCache1");     

在使用ehcache后,需要关闭
CacheManager.getInstance().shutdown()    

caches 的使用
Cache cache = manager.getCache("sampleCache1");     
执行crud操作

Cache cache = manager.getCache("sampleCache1");
Element element = new Element("key1", "value1");
cache.put(element);  

update 
Cache cache = manager.getCache("sampleCache1");
cache.put(new Element("key1", "value1");
//This updates the entry for "key1"
cache.put(new Element("key1", "value2"); 

get Serializable
Cache cache = manager.getCache("sampleCache1");
Element element = cache.get("key1");
Serializable value = element.getValue();

get non serializable
Cache cache = manager.getCache("sampleCache1");
Element element = cache.get("key1");
Object value = element.getObjectValue(); 

remove
Cache cache = manager.getCache("sampleCache1");
Element element = new Element("key1", "value1"
cache.remove("key1");   

7.EhCache在S2SH的用法

1,下载EhCache web版  http://ehcache.org/downloads/catalog  注意下载web版。可见附件

2,解压 将ehcache-web-2.0.3.jar 、ehcache-core-2.3.0.jar  拷入lib中。

3,在src下建立ehcache.xml 

4,开始配置 web.xml ,注意此filter配置应该放在Struts2核心filter的前面。

<!-- 页面缓存配置 ehcache -->
	<filter>
		<filter-name>SimplePageFragmentCachingFilter</filter-name>
		<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter</filter-class>
		<init-param>
			<param-name>suppressStackTrace</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>cacheName</param-name>
			<param-value>SimplePageFragmentCachingFilter</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>SimplePageFragmentCachingFilter</filter-name>
		<url-pattern>/index.action</url-pattern>
	</filter-mapping>

  5,配置ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">
         <diskStore path="java.io.tmpdir"/>
         <cache name="SimplePageFragmentCachingFilter"
  		maxElementsInMemory="10"
  		eternal="false"
  		timeToIdleSeconds="10000"
  		timeToLiveSeconds="10000"
  		overflowToDisk="true">
	</cache>
</ehcache>

    重启服务器,运行页面,第一次访问查询了数据库,此时EhCache将页面的内容缓存,下一次访问的时候,则直接使用缓存中的数据,而不必去访问数据库。一直到缓存过期,才会重新查询数据库。

    总结:ehcache是一个非常轻量级的缓存实现,而且从1.2之后就支持了集群,目前的最新版本是1.3,而且是hibernate默认的缓存provider。虽然本文是介绍的是ehcache对页面缓存的支持,但是ehcache的功能远不止如此,当然要使用好缓存,对JEE中缓存的原理,使用范围,适用场景等等都需要有比较深刻的理解,这样才能用好缓存,用对缓存。



你可能感兴趣的:(ehcache)