ehcache用法总结 1.直接注解在方法上,针对方法进行缓存 @Cacheable(value = "myCache", key = "'getOrderList'+#params['userId']") //设置缓存,key表示参数params(map)中的userId的值 @CachePut(value="myCache",key="'id:'+#p0['id']") //更新缓存,key表示第0个变量(map)中的id的值 @CacheEvict(value = "myCache", key = "'get'+#user.id") //删除指定缓存,key表示对象user中id的值 @CacheEvict(value = "myCache", allEntries = true) //删除全部缓存 颗粒度适中,方便使用 2.拦截器方式缓存 方法前拦截所有get、select等开头否方法缓存下来 方法后拦截所有update、delete等开头的方法,清空缓存 颗粒度太大 3.ehCache和redis结合缓存,比较高级参考http://blog.csdn.net/liaoyulin0609/article/details/51787020 不太稳定,还有报错现象 4.缓存在mybatis方法上 对于我们的环境不太适用,因为还有redis一层 先挑响应时间长的接口优化 再对经常访问且少变化的接口缓存 常量型缓存: 系统配置 系统字典 业务型缓存 订单描述等 其他 原则:缓存优先于redis使用 手动控制写法 System.out.println(ehCacheService.getKeys("myCache"));//缓存名字为myCache的全部缓存 if(StringUtil.isEmpty(ehCacheService.getObject("myCache", "testkey"))){ System.out.println("设置testkey为缓存"); ehCacheService.setObject("myCache", "testkey", "我是testkey"); }else{ System.out.println("读取testkey" + ehCacheService.getObject("myCache", "testkey")); System.out.println("更新testkey"); ehCacheService.setObject("myCache", "testkey", "我是testkey222222222"); } 关于注解有的有效有的无效的说明 经多次测试发现,当一个方法A调用本类中的另一方法B,对B方法进行@cacheable,那么是无效的,如果是调用其他类中的方法C,对方法C进行@cacheable那么是有效的。如果还是想缓存B怎么办呢,改为手动处理缓存吧,只能这样
这坑爹的设计,谁能告诉我为什么,害我在这个问题上研究了一天啊一天 关于缓存的对象变更后,自动更新到缓存中的说明
举例 int num = 1; //缓存到内存 ehCacheService.setObject(num,"conCache", "num"); System.out.println("orderNote="+ehCacheService.getObject("conCache", "num"));//结果为1 num ++; System.out.println("orderNote="+ehCacheService.getObject("conCache", "num"));//结果为2 实际我想要的结果是缓存中的值仍然是1,那么就要用到ehCache的copyOnWrite=“true”、copyOnRead=“true ”并且配置copyStrategy 即可,具体可查看http://blog.csdn.net/haiyang4988/article/details/53216282中的说明。
2016-12-21更新:
这几天测试的时候发现使用注解方式的缓存即使配置copyOnWrite、copyOnRead、copyStrategy也没用,缓存中的值依然被更新,不知道为什么,但是如果改为手动方式实现就没有问题,就是手动太累,能用注解的尽量用注解,不行的再改为手动
以下为转载
http://blog.csdn.net/jadyer/article/details/12257865#
这里用的是SpringMVC-3.2.4和Ehcache-2.7.4
介绍二者集成之前,先介绍下GoogleCode上的ehcache-spring -annotations项目
下面开始罗列示例代码,首先是web.xml
<? xml version = "1.0" encoding = "UTF-8" ?> < web-app version = "2.5" xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> < servlet > < servlet-name > SpringMVC </ servlet-name > < servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class > < init-param > < param-name > contextConfigLocation </ param-name > < param-value > classpath:applicationContext.xml </ param-value > </ init-param > < load-on-startup > 1 </ load-on-startup > </ servlet > < servlet-mapping > < servlet-name > SpringMVC </ servlet-name > < url-pattern > / </ url-pattern > </ servlet-mapping > </ web-app >
然后是//src//applicationContext.xml
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc = "http://www.springframework.org/schema/mvc" xmlns:cache = "http://www.springframework.org/schema/cache" xmlns:context = "http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> < context:component-scan base-package = "com.jadyer" /> < mvc:annotation-driven /> < bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > < property name = "prefix" value = "/" /> < property name = "suffix" value = ".jsp" /> </ bean > < mvc:view-controller path = "/" view-name = "forward:/index.jsp" /> < cache:annotation-driven cache-manager = "cacheManager" /> <!-- < bean id = "cacheManager" class = "org.springframework.cache.support.SimpleCacheManager" > < property name = "caches" > < set > < bean name = "myCache" class = "org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" /> </ set > </ property > </ bean > --> < bean id = "cacheManagerFactory" class = "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" > < property name = "configLocation" value = "classpath:ehcache.xml" /> </ bean > < bean id = "cacheManager" class = "org.springframework.cache.ehcache.EhCacheCacheManager" > < property name = "cacheManager" ref = "cacheManagerFactory" /> </ bean > </ beans >
下面是//src//ehcache.xml
< ehcache > < diskStore path = "java.io.tmpdir" /> < defaultCache maxElementsInMemory = "1000" eternal = "false" timeToIdleSeconds = "120" timeToLiveSeconds = "120" overflowToDisk = "false" /> < cache name = "myCache" maxElementsOnDisk = "20000" maxElementsInMemory = "2000" eternal = "true" overflowToDisk = "true" diskPersistent = "true" /> </ ehcache > <!-- < diskStore > ==========当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口) < diskStore path = "" > ==用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是*.data和*.index name =================缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里) maxElementsOnDisk ====磁盘缓存中最多可以存放的元素数量,0表示无穷大 maxElementsInMemory ==内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况 1)若overflowToDisk = true ,则会将Cache中多出的元素放入磁盘文件中 2)若overflowToDisk = false ,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素 eternal ==============缓存中对象是否永久有效,即是否永驻内存,true时将忽略timeToIdleSeconds和timeToLiveSeconds timeToIdleSeconds ====缓存数据在失效前的允许闲置时间(单位:秒),仅当 eternal = false 时使用,默认值是0表示可闲置时间无穷大,此为可选属性 即访问这个cache中元素的最大间隔时间,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除 timeToLiveSeconds ====缓存数据在失效前的允许存活时间(单位:秒),仅当 eternal = false 时使用,默认值是0表示可存活时间无穷大 即Cache中的某元素从创建到清楚的生存时间,也就是说从创建开始计时,当超过这个时间时,此元素将从Cache中清除 overflowToDisk =======内存不足时,是否启用磁盘缓存(即内存中对象数量达到maxElementsInMemory时,Ehcache会将对象写到磁盘中) 会根据标签中path值查找对应的属性值,写入磁盘的文件会放在path文件夹下,文件的名称是cache的名称,后缀名是data diskPersistent =======是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件 这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存 要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法 diskExpiryThreadIntervalSeconds ==磁盘缓存的清理线程运行间隔,默认是120秒 diskSpoolBufferSizeMB ============设置DiskStore(磁盘缓存)的缓存区大小,默认是30MB memoryStoreEvictionPolicy ========内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存 共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出) -->
下面是需要被缓存处理的UserService.java
package com.jadyer.service; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class UserService { private Map<String, String> usersData = new ConcurrentHashMap<String, String>(); public UserService(){ System.out.println("用户数据初始化..开始" ); usersData.put("2" , "玄玉" ); usersData.put("3" , "我的博客:http://blog.csdn.net/jadyer" ); System.out.println("用户数据初始化..完毕" ); } @Cacheable (value= "myCache" , key= "'get'+#userNo" ) public String get(String userNo){ System.out.println("数据库中查到此用户号[" + userNo + "]对应的用户名为[" + usersData.get(userNo) + "]" ); return usersData.get(userNo); } @CacheEvict (value= "myCache" , key= "'get'+#userNo" ) public void update(String userNo){ System.out.println("移除缓存中此用户号[" + userNo + "]对应的用户名[" + usersData.get(userNo) + "]的缓存" ); } @CacheEvict (value= "myCache" , allEntries= true ) public void removeAll(){ System.out.println("移除缓存中的所有数据" ); } }
下面是UserController.java
package com.jadyer.controller; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.jadyer.service.UserService; @Controller @RequestMapping ( "cacheTest" ) public class UserController { @Resource private UserService userService; @RequestMapping (value= "/get/{userNo}" , method=RequestMethod.GET) public String get( @PathVariable String userNo, Model model){ String username = userService.get(userNo); model.addAttribute("username" , username); return "getUser" ; } @RequestMapping (value= "/update/{userNo}" , method=RequestMethod.GET) public String update( @PathVariable String userNo, Model model){ userService.update(userNo); model.addAttribute("userNo" , userNo); return "updateUser" ; } @RequestMapping (value= "/removeAll" , method=RequestMethod.GET) public String removeAll(){ userService.removeAll(); return "removeAllUser" ; } }
最后把剩下的4个jsp页面列出来,首先是index.jsp
< %@ page language = "java" pageEncoding = "UTF-8" % > 查看< a href = "<%=request.getContextPath()%>/cacheTest/get/2" target = "_blank" > 2号 </ a > 用户名 < br /> < br /> 查看< a href = "<%=request.getContextPath()%>/cacheTest/get/3" target = "_blank" > 3号 </ a > 用户名 < br /> < br /> 更新< a href = "<%=request.getContextPath()%>/cacheTest/update/3" target = "_blank" > 3号 </ a > 用户名 < br /> < br /> 移除< a href = "<%=request.getContextPath()%>/cacheTest/removeAll" target = "_blank" > 所有 </ a > 用户名
下面是getUser.jsp
< %@ page language = "java" pageEncoding = "UTF-8" % > 当前用户名为${username}
下面是updateUser.jsp
< %@ page language = "java" pageEncoding = "UTF-8" % > 已更新${userNo}号用户
最后是removeAllUser.jsp
< %@ page language = "java" pageEncoding = "UTF-8" % > 已移除所有用户
测试 时,访问index.jsp之后点击各个链接并依次观察控制台输出即可 缓存有效果的特征是:第二次查询数据时不会访问数据库 (即不打印日志)