SpringBoot整合Ehcache(Ehcache的使用)

今天捣鼓了下Ehcache,大概弄明白了它的用法,下面就总结记录一下吧。

关于ehcache的介绍这里就不再描述了,给个万能链接自行查阅---->传送门(^.^)。

整合内容:spring2.1+mybatis+druid+ehcache。工具:IDEA2018

首先用IDEA搭建一个Webservice项目。然后往Pom.xml中加入ehcache所需的依赖

        <!-- 缓存支持启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- Ehcache -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

再配置ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

   
    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <cache name="mydict"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>

    <cache name="testdict"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>

在此说明下这些配置项的意思:

diskStore为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数:user.home – 用户主目录;user.dir  – 用户当前工作目录;java.io.tmpdir – 默认临时文件路径
defaultCacheechcache的默认缓存策略;当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如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.minant.mycache.mapper.DictValueMapper">
    <select id="queryByCode" parameterType="com.minant.mycache.form.DictSearchForm"
            resultType="com.minant.mycache.model.DictValueInfo">
        select
          t.dict_code as dictCode,
          t.dict_real_value as realValue,
          t.dict_show_value as showValue,
          t.dict_value_order as dictOrder
        from sm_dict_value_info t
        <where>
            <if test="dictCode != null and dictCode != ''">
               t.dict_code = #{dictCode}
            </if>
        </where>
        <if test="orderType != null and orderType != ''">
            <choose>
                <when test="orderType == 1">
                    ORDER BY t.dict_value_order asc
                </when>
                <when test="orderType == 2">
                    ORDER BY t.dict_value_order desc
                </when>
                <otherwise>
                </otherwise>
            </choose>
        </if>
    </select>
</mapper>

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

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

    @Override
    @Cacheable(value = "testdict", key = "#form.orderType")
    public List<DictValueInfo> 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<DictValueInfo> queryByCode(DictSearchForm form);
List<DictValueInfo> queryAll(DictSearchForm form);
List<DictValueInfo> 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<DictValueInfo> queryByCode(DictSearchForm form) {
            form.setDictCode("cust_type");
            form.setOrderType(1);
            log.info("第一次查询:");
            List<DictValueInfo> custls = dictValueService.queryByCode(form);
            log.info("第二次查询:");
            List<DictValueInfo> custls1 = dictValueService.queryByCode(form);
            log.info("第三次查询:");
            form.setDictCode("cert_type");
            List<DictValueInfo> 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<DictValueInfo> 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!

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值