EHCachey应用

来源:互联网 发布:C语言如何创建线程 编辑:程序博客网 时间:2024/04/29 19:24

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();//添加Cachecm.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.MySQLInnoDBDialecthibernate.show_sql=truehibernate.format_sql=falsehibernate.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层代码中使用缓存了:

@Repositorypublic 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的使用真的很简单。

任何需要积分的下载都是耍流氓

0 0