今天捣鼓了下Ehcache,大概弄明白了它的用法,下面就总结记录一下吧。
关于ehcache的介绍这里就不再描述了,给个万能链接自行查阅---->传送门(^.^)。
整合内容:spring2.1+mybatis+druid+ehcache。工具:IDEA2018
首先用IDEA搭建一个Webservice项目。然后往Pom.xml中加入ehcache所需的依赖。
org.springframework.boot
spring-boot-starter-cache
net.sf.ehcache
ehcache
再配置ehcache.xml
在此说明下这些配置项的意思:
diskStore | 为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数:user.home – 用户主目录;user.dir – 用户当前工作目录;java.io.tmpdir – 默认临时文件路径 |
defaultCache | echcache的默认缓存策略;当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个 |
eternal | 缓存中对象是否永久有效;设置了,timeout将不起作用 |
overflowToDisk | 是否保存到磁盘,当系统宕机时 |
timeToIdleSeconds | 缓存数据在失效前的允许闲置时间(单位:秒);仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除 |
timeToLiveSeconds | 缓存数据的总的存活时间(单位:秒),仅当eternal=false时使用,默认是0.,也就是对象存活时间无穷大。 |
maxElementsOnDisk | 磁盘缓存中最多可以存放的元素数量,0表示无穷大 |
diskPersistent | 是否缓存虚拟机重启期数据,默认为否 |
diskSpoolBufferSizeMB | 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
diskExpiryThreadIntervalSeconds | 磁盘失效线程运行时间间隔,默认是120秒 |
memoryStoreEvictionPolicy | 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用) |
clearOnFlush | 内存数量最大时是否清除 |
memoryStoreEvictionPolicy | 内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数) |
: 上方我所配置的一个默认的,两个测试用的 mydict、testdict。
xml配置完成之后,yml配置文件中要加上缓存配置:
SpringBoot启动类上也要开启缓存,加上注解@EnableCaching:
接下来就可以开始编写业务代码了。这里我只做了一个字典码值查询来测试。
SQL如下:
Service实现:
package com.minant.mycache.service;
import com.minant.mycache.form.DictSearchForm;
import com.minant.mycache.mapper.DictValueMapper;
import com.minant.mycache.model.DictValueInfo;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* @ClassName DictValueServiceImpl
* @Description TODO DictService实现
* @Author MinAnt
* @Date 2020/5/15
* @Version V1.0
*/
@Service("dictValueService")
public class DictValueServiceImpl implements DictValueService {
private static Logger logger = LoggerFactory.getLogger(DictValueServiceImpl.class);
@Autowired
private DictValueMapper dictValueMapper;
@Autowired
private ApplicationContext applicationContext;
@Override
@Cacheable(value = "mydict", key = "#form.orderType")
public List queryByCode(DictSearchForm form) {
return dictValueMapper.queryByCode(form);
}
/**
* 手动获取缓存信息
* 可自定义添加缓存
* */
@Override
public void showCache() {
// 双得检查单例模式获取
/*CacheManager cacheManager = CacheManager.create(DictValueServiceImpl.class.getClassLoader()
.getResourceAsStream("ehcache.xml"));*/
// getBean方式获取
CacheManager cacheManager = applicationContext.getBean(CacheManager.class);
Cache cache = cacheManager.getCache("mydict");
List
List queryByCode(DictSearchForm form);
List queryAll(DictSearchForm form);
List queryTestAll(DictSearchForm form);
为了偷懒,这里分了三个方法查,这么做是为了测试不周缓存注解的作用;这里测了三个注解:
@Cacheable
@CachePut
@CacheEvict
@Cacheable如果在缓存中发现相同的key则会从缓存中取数据。@CachePut每次都会重新执行,然后将结果放入缓存。@CacheEvict表示清除缓存。
详情请移步到一位前辈的总结文章:https://www.jianshu.com/p/db110523a387
其中详细的描述了注解的参数及其用法,在此也不再一一列举了。
继续我的测试,先说说这几个方法是干嘛的。
/**
* 按码值查询字典信息
* key为orderType所有当orderType一直相同时,都走的是缓存
* */
@RequestMapping("/queryByCode")
public List queryByCode(DictSearchForm form) {
form.setDictCode("cust_type");
form.setOrderType(1);
log.info("第一次查询:");
List custls = dictValueService.queryByCode(form);
log.info("第二次查询:");
List custls1 = dictValueService.queryByCode(form);
log.info("第三次查询:");
form.setDictCode("cert_type");
List certls = dictValueService.queryByCode(form);
return certls;
}
这段是Controller中的调用代码,这里把码值先设定为cust_type,orderType设为1,下面连查了两次相同的,然后改变码值为cert_type后又查了一遍。其运行的结果是只有第一次查询打印了SQL日志,说明这第一次是从库中查询所得,面后续的查询结果都是直接从缓存中返回的。而对于最终的返回结果,理应是cert_type对应的值,然而却是和第一第二次查询相同时的结果,是cust_type的结果,这就是因为之前设置的缓存key是orderType,这里三次查询的OrderType都是1所以就会有这样的结果。
queryAll方法是用来给两个绶存刷新数据用的,也就是@CachePut的作用。怎么测呢?
/**
* 模拟查询所有,orderType都是0
* 同时加入mydict 和 testdict
* */
@RequestMapping("/queryAll")
public List queryAll(DictSearchForm form) {
form.setOrderType(0);
return dictValueService.queryAll(form);
}
这是Controller层的调用代码。既然是测@CachePut,它的作用是每次调用都会往缓存中刷新数据,同样这里在service实现的方法上定义的key是orderType,Controller中固定死了这个值,那么也就是每次调用都是相同的查询,看其每次调用的时候是不是都会打印SQL日志就知道是不是每次都走库查询,结果是肯定的。至于是不是每次都会刷新这两个缓存的数据,可以先调queryTestAll方法(用来查询testdict缓存块的方法),传同样的orderType=0为参,因为queryAll已刷入缓存数据,所以它是不会打印SQL的,由此获取到结果记录下来。再到库中修改一些相关的数据,再执行一次queryAll,再调queryTestAll方法,传同样的orderType=0为参,会发现没有打印SQL,但数据已经是库中修改过的最新数据,这说明执行的queryAll方法刷新了一次testdict缓存。
clearCache方法,用来清除mydict的所有缓存;
clearTestCache方法,用来清除testdict的所有缓存;
测试这两个清除缓存的方法也就是测 @CacheEvict注解。测试方式,在之前执行的queryAll方法后,两个缓存块中都有数据,然后调clearTestCache,清除testdict缓存,再调queryTestAll方法,传同样的orderType=0,会打印出SQL说明走了库查询,说明缓存数据清除成功了。
至此结束。
Stay Hungry Stay Foolish!