听说你还在用 SpringBoot 整合 redis 框架? 不确定试试 ehcache 缓存?

91 阅读6分钟

一、简介

(1)Ehcache 缓存简介

    Ehcache 是一个纯Java的进程内缓存框架,具有快速上手简单等特点,是 hibernate 中默认的缓存提供方;

image.png

(2)hibernate 缓存

hibernate 三级缓存机制简介:

  1. 一级缓存:基于 session 级别分配一块缓存空间,缓存访问的对象信息。session 关闭后会自动清除缓存。
  2. 二级缓存:是 sessionFactory 对象缓存,可以被创建多个 session对象共享,二级缓存默认是关闭的,如果需要使用需要手动开启,并且依赖 Ehcache 组件。
  3. 三级缓存:查询缓存,配置开启改缓存的情况下,重复使用下一个 SQL 查询某个范围内数据,会进行缓存。
(3)Ehcache 缓存特点
  • 快速、简单、并且提供多种缓存策略;

  • 缓存数据有两级:内存 和 磁盘,无需担心容量问题;

  • 缓存数据会在虚拟机重启的过程中写入磁盘;

  • 可以通过 RMI、可插入API 等方式进行分布式缓存;

  • 具有缓存和缓存管理器的侦听接口;

  • 支持多缓存管理器实例,以及一个实例的多个缓存区域;

  • 提供 hibernate 的缓存实现;

(4)Ehcache 和 redis 区别
  1. Ehcache:直接 再 JVM 虚拟中缓存,速度快,效率高,不适合处理大规模缓存数据,在分布式环境下,缓存数据共享操作复杂;

  2. Redis:作为独立的缓存中间件,在分布式缓存系统中非常好用,缓存数据共享,有效支撑大量数据缓存,支持哨兵模式,集群模式 等高可用的成熟方案;

二、SpringBoot 整合 Ehcache

(1)引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
(2)配置application.yml
spring:
  cache:
    ehcache:
      config: classpath:ehcache.xml
(3)编写 ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置,可以自定义目录,确保用户有权限即可。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <!-- 操作系统缓存的临时目录,内存满后写入该目录 -->
    <diskStore path="java.io.tmpdir"/>
    <!-- <diskStore path="C:/Users/admin/ehcache/"/> -->

    <defaultCache
                  maxElementsInMemory="1000"
                  eternal="false"
                  timeToIdleSeconds="120"
                  timeToLiveSeconds="120"
                  maxElementsOnDisk="10000000"
                  diskExpiryThreadIntervalSeconds="120"
                  memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
	
    <!-- 注意:这里的 userEntity 需要和 @Cacaheable 中的 value 或 cacheNames 对应上 -->
    <cache name="userEntity" 
           maxElementsInMemory="1000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
    
    <!-- maxElementsInMemory:内存中最大缓存对象数,根据服务器资源配置 -->
    <!-- eternal: 默认为false,设置true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性, -->
    <!-- maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大 -->
    <!-- overflowToDisk:true表示当内存缓存的对象数目达到了maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。
    注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。-->
    <!-- diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。-->
    <!-- diskPersistent:是否缓存虚拟机重启期数据  -->
    <!-- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒 -->

    <!-- timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,单位(秒)。自对象最近一次被访问后,
    空闲时间超过了timeToIdleSeconds属性值,这个对象就会过期,如果该属性值为0,则对象无限期地处于空闲状态
    EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。
    -->

    <!-- timeToLiveSeconds:设定允许对象存在于缓存中的最长时间,单位(秒)。自对象被存放到缓存中后,
    在缓存中的时间超过了timeToLiveSeconds属性值,这个对象就会过期,如果该属性值为0,则对象无限期地存在于缓存中。
    EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义 -->

    <!-- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。
    可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。-->
</ehcache>

配置参数说明:

  • maxElementsInMemory:磁盘缓存中最多可以存放的元素数量;
  • eternal:缓存中对象是否永久有效;
  • timeToIdleSeconds:当 eternal=false 时使用,缓存数据有效期(单位:秒),时间段内没有访问该元素,将被清除;
  • timeToLiveSeconds:缓存数据的存活时间;
  • maxElementsInMemory:内存中最多可以存放的元素数量,overflowToDisk=true,则会将 Cache 中多出的元素放入磁盘文件中,若 overflowToDisk=false,则根据 memoryStoreEvictionPolicy 策略替换 Cache 中原有的元素;
  • diskExpiryThreadIntervalSeconds:磁盘缓存的清理线程运行间隔;
  • memoryStoreEvictionPolicy:缓存释放策略,LRU 会优先清理最少使用的缓存;
  • localTempSwap:持久化策略,当堆内存或者非堆内存里面的元素已经满了的时候,将其中的元素临时的存放再磁盘上,重启后就会消失;
(4)添加启动类注解
@EnableCaching // Ehcache 开启注解
@SpringBootApplication
public class Application {
    public static void main(String[] args) {SpringApplication.run(Application.class,args) ;}
}
(5)使用示例
@Service
public class CacheService {
	private static final Logger LOGGER = LoggerFactory.getLogger(CacheService.class);
    
    @Resource
    private UserMapper userMapper;

    // 在缓存有效期内,首次查询才访问数据库
    @Cacheable(value="userEntity")
    public UserEntity getById(Integer id) {
    	LOGGER.info("getById..." + id); // 通过日志,标识方法是否执行
        return userMapper.selectById(id);
    }

    // 该ID数据数据更新,清空该ID缓存
    @CacheEvict(value="userEntity", key="#id")
    public void updateUser(Integer id) {
    	UserEntity user = new UserEntity();
        user.setId(id);
        user.setUserName("myName");
        userMapper.updateById(user);
    }

}

注解详解:

  • @Cacheable:注解标记在一个方法上,也可以标记在一个类上。(标记在一个方法上 标识该方法支持缓存,该方法被调用后将其返回值缓存起来,下次同样的请求参数职系那个该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。)

  • @CacheEvit:注解标记在需要清除缓存元素的方法或类上的。(标记在类上时,表示其中所有的方法的执行都会触发缓存的清除操作,并且可以按照指定属性清除。)

  • @CacheConfig:声明在类上,指定本类上所有使用缓存的方法的缓存名称,如有注解@Cacheable的方法。

  • @Cacheable:使用@Cacheable注解的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,如果存在则执行方法,并将返回结果存入指定的缓存中

  • @CachePut:使用@CachePut注解的方法,Spring在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中;

    @CachePut(key = "#user.id")
    public User updateUserById(User user) {
        return user;
    }
    
  • @CacheEvict清除缓存,属性allEntries为true则删除所有缓存,属性beforeInvocation表示缓存的清除是在方法前执行还是方法后执行,默认是为false,方法执行后删除;

    @CacheEvict(beforeInvocation=false)
    public void deleteUserById(Integer id) {
        //去数据库中删除(CacheEvict 属性 beforeInvocation=false 在删除数据库之后删除,=true则是删除数据库之前删除)
    }
    
  • @Caching分组注解,可以包含多个@Cacheable和@CachePut,一般在复杂业务的情况下使用

附录