Spring Cache

Spring Cache 是在 Spring 3.1 中引入的基于注释(Annotation)的缓存(Cache)技术,它本质上不是一个具体的缓存实现方案,而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 Annotation,即能够达到缓存方法的返回对象的效果。

通常我们在缓存中使用逻辑判断,先判断缓存中是否存在数据,然后在根据是否存在去数据库中查询。
这样子也能实现功能,但是往往业务系统中存在大量的缓存,每个缓存我们都需要去逻辑判断,再去读库。

这样子大量的逻辑判断代码,不是很优雅。

这时候Spring Cache 就提供了一种很优雅的缓存方式,基于注解的缓存方式,配合spl表达式,很灵活的进行缓存设置。
它的原理是 Spring Cache 利用了 Spring AOP 的动态代理技术,在项目启动的时候动态生成它的代理类,在代理类中实现了对应的逻辑。

SpEL(Spring Expression Language)是一个支持运行时查询和操作对象图的强大的表达式语言,其语法类似于统一 EL,但提供了额外特性,显式方法调用和基本字符串模板函数。

Spring Boot 中 Cache 的使用

三个核心的注解

@Cacheable、@CacheEvict、@CachePut

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

在main方法上开启缓存

@EnableCaching

1 @Cacheable

@Cacheable 用来声明方法是可缓存的,将结果存储到缓存中以便后续使用相同参数调用时不需执行实际的方法,直接从缓存中取值。@Cacheable 可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

@RequestMapping("/user/{id}")
    @Cacheable(key = "#id",value = "user")
    public User getUser(@PathVariable String id) {

        return userService.getUserById(id);
    }

意思是: 调用这个方法时候,先从 名为user的缓存中查找id的数据,存在直接返回,不存在再去数据库中查询,再将结果存在缓存对象中。

  • @Cacheable 支持如下几个参数。

value:缓存的名称。
key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写;如果不指定,则缺省按照方法的所有参数进行组合。
condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持 SpEL。

@RequestMapping("/user/{id}")
       @Cacheable(key = "#id",value = "user",condition = "#id>4")
    public User getUser(@PathVariable String id) {

        return userService.getUserById(id);
    }

id 大于 4的时候才进行缓存,否则直接走数据库查询。

  • @Cacheable 总结

当执行到一个被 @Cacheable 注解的方法时,Spring 首先检查 condition 条件是否满足,如果不满足,执行方法,返回;如果满足,在缓存空间中查找使用 key 存储的对象,如果找到,将找到的结果返回,如果没有找到执行方法,将方法的返回值以 key-value 对象的方式存入缓存中,然后方法返回。

2 @CachePut

当数据发生变化时,我们需要将缓存清楚,重新查询后放入缓存中,保持数据一致。

所以,这时候我们需要这么做, @CachePut 就为我们提供了这个功能。

@RequestMapping("/up/{id}")
    @CachePut(key = "#id",value = "user")
    public User update(@PathVariable int id) {

        return userService.getUserById(id);
    }

意思是:每次调用 "/up/{id} 方法时候都需要进行,查询数据,然后再将结果放入 user的缓存中名为id的这条数据。

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

需要注意的是: 更新缓存的 key 和 value 要保持一致,存放缓存数据的缓存管理器要一致,缓存管理器中的id要保持一致。

  • @CachePut 配置方法

value 缓存的名称。
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。
可以看出 @CachePut 的参数和使用方法基本和 @Cacheable 一致。

@CachePut 也可以标注在类上和方法上。
@Cacheable 先查缓存,没有在去查询数据库,@CachePut 先从数据库查询 在放入缓存中。

3 @CacheEvict

当然我们不需要某条数据时候,从数据库中删除,也需要从缓存中删除数据。

  • @CacheEvict 提供这个功能

@CacheEvict 是用来标注在需要清除缓存元素的方法或类上的,当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict 可以指定的属性有 value、key、condition、allEntries 和 beforeInvocation,其中 value、key 和 condition 的语义与 @Cacheable 对应的属性类似。

即 value 表示清除操作是发生在哪些 Cache 上的(对应 Cache 的名称);key 表示需要清除的是哪个 key,如未指定则会使用默认策略生成的 key;condition 表示清除操作发生的条件。下面来介绍一下新出现的两个属性 allEntries 和 beforeInvocation。

  • 删除缓存和数据库中的数据
    key = “#id”,value = “user” 必须与查询和更新 key 和 value一致

要么都写,写一样的。 key 可以不写,不写都不要写,Spring Boot 会以默认的 key 值去更新缓存,存入缓存中的key不一致,找不到key,就不会删除需要删除的缓存数据。

@RequestMapping("/de/{id}")
    @CacheEvict(key = "#id",value = "user")
    public void deleteByid(@PathVariable String id) {
         userService.deleteUserById(id);
    }
  • allEntries
    默认为false 不删除全部缓存数据,true 表示删除全部数据

@CacheEvict(value = "user",allEntries = true)

  • beforeInvocation 属性

清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用 beforeInvocation 可以改变触发清除操作的时间,当我们指定该属性值为 true 时,Spring 会在调用该方法之前清除缓存中的指定元素。

@RequestMapping("/beforeInvocation")
@CacheEvict(value="usersCache", allEntries=true, beforeInvocation=true)
public void beforeInvocation() {
    throw new RuntimeException(" beforeInvocation");
}

4 最后

@Cacheable 作用和配置方法

主要针对方法配置,能够根据方法的请求参数对其结果进行缓存:

主要参数

解释

举例

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

如 @Cacheable(value=“mycache”) 或者 @Cacheable(value={“cache1”,“cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

如 @Cacheable(value=“testcache”,key="#userName")

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

如 如 @Cacheable(value=“testcache”,condition="#userName.length()>2")

@CachePut 作用和配置方法

@CachePut 的作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用。

主要参数

解释

举例

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

如 @Cacheable(value=“mycache”) 或者 @Cacheable(value={“cache1”,“cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

如 @Cacheable(value=“testcache”,key="#userName")

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

如 @Cacheable(value=“testcache”,condition="#userName.length()>2")

@CacheEvict 作用和配置方法

主要针对方法配置,能够根据一定的条件对缓存进行清空。

主要参数

解释

举例

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

如 @CachEvict(value=“mycache”) 或者 @CachEvict(value={“cache1”,“cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

如 @CachEvict(value=“testcache”,key="#userName")

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存

如 @CachEvict(value=“testcache”,condition="#userName.length()>2")

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

如 @CachEvict(value=“testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,

如果方法执行抛出异常,则不会清空缓存 如 @CachEvict(value=“testcache”,beforeInvocation=true)