说明
今天在做统计报表的时候,考虑到数据比较多,所以在项目中集成ehCache减轻数据库请求压力。看似简单,网上参考也比较多,但是还遇到了几处坑,在此记录一下。 ⊙﹏⊙b
随手笔记,比较简单,想要具体了解的可以网上看看大神的博客
问题
(1)、springboot集成了ehcache,配置了过期时间timeToIdleSeconds,发现就是不生效,问度娘后才知道需要在properties文件中指定缓存类型,不然spring boot 使用默认SimpleCacheConfiguration,不是用的ehcache。
(2)、测试的时候第一次请求接口返回正常数据,第二次查询缓存的时候会报java.io.Serializable这个错,是因为我返回的实体类没做序列化。
解决方案在下面
1、首先引入依赖在pom.xml文件中
<!--开启 cache 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- ehcache 缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
2、引入配置文件 ehcache.xml(自己手残名字写错ehcach,导致启动报错,加载不到配置,懵逼。。。。。)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<!--defaultCache:echcache的默认缓存策略 -->
<!--
缓存配置
diskStore:指定数据在磁盘中的存储位置。
name:缓存名称。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略,以下属性是必须的:
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache name="userCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</cache>
</ehcache>
3、在properties文件中指定缓存类型和加载xml,也就是我上面说的问题 ”(1)“。xml也可以用@ImportResource注解直接在spring boot启动类配置。
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:META-INF/mybatis/ehcache.xml
4、在spring boot 启动类也要开启缓存注解@EnableCaching,否则缓存不生效。如下
5、以上集成工作已经完成,那如何在代码中使用呢? 如下
/**
* 查询请求记录数据统计
*
* @param docNos
* @return
*/
@Cacheable(key = "#startDate+'-'+#endDate+'-'+#type",value="userCache")
public ResponseMessage<List<Map<String, Object>>> selectReport(String startDate, String endDate, String docTemplateCode,String type) {
ResponseMessage<List<Map<String, Object>>> rsdto = new ResponseMessage<>();
List<Map<String, Object>> list=new ArrayList<>();
if(StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
ResponseUtil.setResult(rsdto, null, ErrorCodeEnum.PARAMERROR, false);
return rsdto;
}
/*if(StringUtils.isBlank(docTemplateCode)) {
ResponseUtil.setResult(rsdto, null, ErrorCodeEnum.PARAMERROR, false);
return rsdto;
}*/
if(StringUtils.isBlank(type)) {
ResponseUtil.setResult(rsdto, null, ErrorCodeEnum.PARAMERROR, false);
return rsdto;
}
Integer length=0;
try {
length= ReportTypeEnum.getEnum(type).getValue();
list=docRecordTunnel.selectReportByDateTime(startDate, endDate, docTemplateCode, length);
ResponseUtil.setResult(rsdto, list, ErrorCodeEnum.SUCCESS,true);
} catch (Exception e) {
log.error("DocRecordController.selectReport查询失败", e);
ResponseUtil.setResult(rsdto, null, ErrorCodeEnum.ERROR, false);
}
return rsdto;
}
注: 返回的实体类需要做序列化,否则查询缓存的时候会报错。如下图
一般情况下,我们在Sercive层进行对缓存的操作。先介绍 Ehcache 在 Spring 中的注解:
* @Cacheable : Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。
* @CacheEvict : 清除缓存。
* @CachePut : @CachePut也可以声明一个方法支持缓存功能。使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
简单来说,Cacheable 一般用于查询,CacheEvict 用于新增清除缓存,CachePut 用于更新;其中,value 指的是 ehcache.xml 中的缓存策略空间;key 指的是缓存的标识,同时可以用 # 来引用参数。上面代码引用参数为多个组合作为缓存key 。
5、启动项目,测试结果。具体代码我就不再贴了。