SpringBoot整合Ehcache(Ehcache的使用)

今天捣鼓了下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整合Ehcache(Ehcache的使用)_第1张图片

SpringBoot启动类上也要开启缓存,加上注解@EnableCaching:

SpringBoot整合Ehcache(Ehcache的使用)_第2张图片

接下来就可以开始编写业务代码了。这里我只做了一个字典码值查询来测试。

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 keys = cache.getKeys();
        Map results = cache.getAll(keys);
        Element element = cache.get("0");
    }

    @Override
    @CachePut(value = {"mydict","testdict"}, key = "#form.orderType")
    public List queryAll(DictSearchForm form) {
        logger.info("更新缓存!!");
        return dictValueMapper.queryByCode(form);
    }

    @Override
    @Cacheable(value = "testdict", key = "#form.orderType")
    public List queryTestAll(DictSearchForm form) {
        return dictValueMapper.queryByCode(form);
    }

    /**
     * 清除mydict所有缓存
     * beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素
     * allEntries 。表示是否需要清除缓存中的所有元素,忽略key,清除Value的所有
     * */
    @Override
    @CacheEvict(value = "mydict", allEntries = true, beforeInvocation = true)
    public Integer clearCache() {
        logger.info("缓存mydict清除成功!!");
        return 1;
    }

    @Override
    @CacheEvict(value = "testdict", allEntries = true, beforeInvocation = true)
    public Integer clearTestCache() {
        logger.info("缓存testdict清除成功!!");
        return 1;
    }
}
 
  
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

其中详细的描述了注解的参数及其用法,在此也不再一一列举了。

继续我的测试,先说说这几个方法是干嘛的。

  1. queryByCode方法是查询某个码值的展示值与真实值信息的方法,通过它可以测@Cacheable。例如这里我指定的key为参数对象的orderType属性,即在第一次查询后,当再次查询时参数orderType相同则会直接走缓存按第一次查询得到的结果返回。例如:
    /**
         * 按码值查询字典信息
         * 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所以就会有这样的结果。

  2. 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缓存。

  3. clearCache方法,用来清除mydict的所有缓存;

  4. clearTestCache方法,用来清除testdict的所有缓存;

测试这两个清除缓存的方法也就是测 @CacheEvict注解。测试方式,在之前执行的queryAll方法后,两个缓存块中都有数据,然后调clearTestCache,清除testdict缓存,再调queryTestAll方法,传同样的orderType=0,会打印出SQL说明走了库查询,说明缓存数据清除成功了。

至此结束。

Stay Hungry Stay Foolish!

 

 

 

你可能感兴趣的:(SpringBoot,Ehcache)