Skip to content

缓存

Redis 缓存的操作由 Spring 提供,我们可以通过 RedisTemplate注解形式使用。

配置

yaml
spring:
  # redis 配置
  redis:
    # 地址
    host: 127.0.0.1
    # 端口,默认为6379
    port: 6379
    # 数据库索引
    database: 0
    # 密码
    password: pass
    # 前缀
    prefix: "foo:"
    # 连接超时时间
    timeout: 10s
    jedis:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 0
        # 连接池中的最大空闲连接
        max-idle: 2
        # 连接池的最大数据库连接数
        max-active: 2
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
  cache:
    redis:
      key-prefix: "foo:"
      time-to-live: 3600000

注意

需要特别注意,两个缓存前缀(高亮行)必须保持一致,且不能与其它项目相同。

RedisTemplate

RedisTemplate 是 Spring 提供的对各种 Redis 连接库(Jedis/JRedis/RJC)的封装,提供了统一的接口和功能增强。

相关操作进行了归类封装,针对不同的 Redis 数据类型封装为不同的 Operation 接口。

  • ValueOperations:简单K-V操作

  • SetOperations:set类型数据操作

  • ZSetOperations:zset类型数据操作

  • HashOperations:map类型的数据操作

  • ListOperations:list类型的数据操作

使用示例

java
@Autowired
private RedisTemplate redis

// 1、删除单个key
redis.delete(key);

// 2、删除多个key
public void deleteKey (String ...keys){
    redis.delete(keys);
}

// 3、指定key的失效时间
redis.expire(key,time,TimeUnit.MINUTES);

// 4、根据key获取过期时间
redis.getExpire(key);

// 5、判断key是否存在
redis.hasKey(key);

//3、通过ValueOperations设置值
redis.opsForValue().set("StringKey", "StringVaule");
redis.opsForValue().set("StringValue","StringVaule",1, TimeUnit.MINUTES);

//3、通过ValueOperations获取值
String str3 = (String) redis.opsForValue().get("StringKey");

Spring Cache

Spring Cache 更进一步,对各种缓存方案(redis/ehcache/jcache等)进行抽象封装,统一API。 同时与 AOP 紧密结合,使用注解即可轻松操作缓存。

缓存注解

注解类别说明
@Cacheable设置缓存将方法执行结果进行缓存,存在缓存则不再执行方法
@CachePut设置缓存将方法执行结果进行缓存,不影响方法执行
@CacheEvict删除缓存清除缓存
@Caching组合操作组合多个缓存操作注解
@CacheConfig统一配置类级别注解,比如统一设置cacheNames

@Cacheable

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

属性/方法名:

  • cacheNames 缓存分组名,必填,作为缓存键一部分,可以根据它删除一组缓存
  • value 同cacheNames
  • key 可选属性,使用 SpEL 自定义缓存的key
  • keyGenerator key的生成器。key/keyGenerator二选一使用
  • condition 条件符合则缓存,使用 SpEL
  • unless 条件符合则不缓存,使用 SpEL
  • sync 是否使用异步模式,默认为false

@CachePut

使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。

属性/方法名:

  • value 同cacheNames
  • cacheNames 缓存分组名,必填,作为缓存键一部分,可以根据它删除一组缓存
  • key 可选属性,使用 SpEL 自定义缓存的key
  • keyGenerator key的生成器。key/keyGenerator二选一使用
  • condition 条件符合则缓存,使用 SpEL
  • unless 条件符合则不缓存,使用 SpEL

@CacheEvict

使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上

属性/方法名

  • value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
  • cacheNames 与 value 差不多,二选一即可
  • key 可选属性,使用 SpEL 自定义缓存的key
  • keyGenerator key的生成器。key/keyGenerator二选一使用
  • condition 条件符合则缓存,使用 SpEL
  • allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
  • beforeInvocation 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

@Caching

该注解可以实现同一个方法上同时使用上述注解。

@CacheConfig

当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"cacheName"})注解在 class 之上来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。

使用示例

java
@Component
@CacheConfig(cacheNames = {"toys"}) // 假设缓存前缀已设置为"foo:",那么这时会继续拼接上“toys::"
public class CacheTestService {

    // 默认根据方法所有参数生成key,空参数时应该手动设置key
    @Cacheable("'list'")
    public Map getList(){
        System.out.println("call db exec list");
        Map<String, String> map = new HashMap<>();
        map.put("p1", "hello");
        map.put("p2", "world");

        return map;
    }

    @CacheEvict(allEntries = true) // 删除所有toys分组内缓存
    public void addOne(String id, String name){
        System.out.println("call add one");
    }
}

可以看到,使用注解操作缓存非常清爽,对业务没有侵入性。推荐使用此方式,但需要注意仔细设计缓存key,防止缓存过多。