简介

平时大家使用redis一般都是直接存储key,value.
spring全家桶肯定帮大家想到了这一点.可以让大家方便的使用注解操作redis节省代码量.

把总结放前面:
总共有三种方式,底层利用了spring的aop,并且方法返回的对象一定要实现序列化

  • @Cacheable:注解于方法上,第一次会把后面的cacheNames+key 拼接为key,把返回值序列化后作为value set到redis中去.后面再一次访问相同的key的时候就直接从redis中取值了,不会再访问这个方法
@Override
@Cacheable(cacheNames = "product",key = "#id")
public ProductInfo findOne(String id) {
   return productInfoRepository.findById(id).orElse(null);
}
  • @CachePut:每次都会把方法的返回值序列化之后set到redis中去(每次都会执行方法),即更新这个key对应的值
@Override
    @CachePut(cacheNames = "product",key = "#productId")
    public ProductInfo onSale(String productId) {
        ProductInfo productInfo = this.findOne(productId);
        if(null == productInfo){
            throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
        }

        if(productInfo.getProductStatusEnum().getCode() == ProductStatusEnum.UP.getCode()){
            log.warn("[商品上架处理]-----商品已经是上架状态了,这里直接返回原ProductInfo={}",productInfo);
        }else {
            productInfo.setProductStatus(ProductStatusEnum.UP.getCode());
            productInfo = this.save(productInfo);
        }
        return productInfo;
    }
  • @CacheEvict:这个比较好理解,就是从redis中把这个key删除了
@Override
@CacheEvict(cacheNames = "product",key = "#productInfo.productId")
public ProductInfo save(ProductInfo productInfo) {
    return productInfoRepository.save(productInfo);
}

这里的key其实可以不写,比如上面的@CacheEvict中不写的话就会把参数默认为key,即下面的productInfo对象

一次驱逐多个redis的key

@Caching(evict={
			@CacheEvict(value = Cache.CONSTANT, key = "'" + CacheKey.SINGLE_ROLE_NAME + "'+#roleId"),
            @CacheEvict(value = Cache.CONSTANT, key = "'" + CacheKey.ROLES_NAME + "'+#roleId"),
            @CacheEvict(value = Cache.CONSTANT, key = "'" + CacheKey.SINGLE_ROLE_NAME + "'+#roleId")
            })
public ResponseData remove(@RequestParam Long roleId) {
………………
}

用cacheManager手动put key和value

@Autowired
private CacheManager cacheManager;
...
cacheManager.getCache(PortalConstants.CACHE_PORTAL_MOBILE_VERIFICATION_CODE).put(key, verificationCode);

使用注解前现在启动类中加上@EnableCaching注解

这个注解是spring的,在spring-boot-starter-web包中.一般使用springmvc的都在springboot中引入这个依赖了,所以不用另外引入依赖了.

如果你想单独引入这个依赖的话

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

spring缓存注解redis spring cacheable redis_redis

可以加在方法上使用@Cacheable set value到redis

使用@Cacheable后,第一次会把后面的cacheNames+key 拼接为key,把返回值序列化后作为value set到redis中去.后面再一次访问相同的key的时候就直接从redis中取值了,不会再访问这个方法,也就不会再从数据库中取值了

可以把方法中的参数拼到key上,在这个方法运行完后会把这个方法的返回值根据@Cacheable注解中的cacheNames+key拼接后的值为key,set到redis中取,下次再访问这个key的时候直接从redis中取数据,不用去mysql查找一遍了

spring缓存注解redis spring cacheable redis_spring_02


redis中缓存的key

spring缓存注解redis spring cacheable redis_spring_03

使用condition,对传入的参数进行,筛选只允许符合条件的请求set到redis中

对于现实的需求,肯定有些时候是异常请求,是不需要缓存到redis中的,这里我们也可以使用condition加上判断,判断通过的时候才允许缓存到redis

spring缓存注解redis spring cacheable redis_缓存_04

有根据请求筛选,那么自然也就有根据方法的结果筛选的,根据结果筛选可以使用unless

spring缓存注解redis spring cacheable redis_缓存_05


@Cacheable中,unless参数的作用是:函数返回值符合表达式条件的,veto(否决)、不缓存

换句话说,函数返回值符合条件的排除掉、只缓存其余不符合条件的

若是想要某种条件下才缓存,那么可以在el表达式中对其他情况取反就行了

例如,想要返回结果中productId = 1的,那么可以这样写
@Cacheable(cacheNames = “product111”,key = “#productInfo.productId”, unless = “!#result.productId.equals(‘1’)”)
把结果中不等于1的排除掉,那么剩下的就是等于1了
这里可能有点绕,因为unless自动在最外面取了个反,所以要双重否定
简单说就是对你想要的结果取反,unless自己外面有取反!!2个取反就还是原先的结果

@CachePut 更新value到redis

@CachePut和@Cacheable的相同点都可以加在方法上

不同之处在于@CachePut是每次都会把方法的返回值序列化之后set到redis中去(每次都会执行方法),即更新这个key对应的值,适合用于修改值的方法

spring缓存注解redis spring cacheable redis_缓存_06

这里要注意一点参数里的key后面支持spel表达式,可以从下面的方法中获取参数,然后类型和获取的参数的类型是一样的,虽然外面的双引号,但是里面你直接给个数字,它会当成int去处理的,int的话就会有上限2^31 -1

spel表达式介绍

比如,下图中key就为String类型的字符串

spring缓存注解redis spring cacheable redis_缓存_07

而下图中key的值就是int类型的

spring缓存注解redis spring cacheable redis_缓存_08

@CacheEvict 从redis中删除 key

这个也比较好理解,就是从redis中把这个key删除了

这里的key其实可以不写,不写的话就会把参数默认为key,即下面的productInfo对象

spring缓存注解redis spring cacheable redis_缓存_09

使用@CacheConfig注解可以让多个方法使用统一的cacheNames

如果在同一个类中,要使用redis缓存的每个方法中都要写cacheNames是不是觉得很麻烦,可以使用@CacheConfig(cacheNames = “product”),为下面的注解默认使用上面这个CacheConfig中定义的cacheNames

这个和css中的作用域一样,如果方法上的注解有自己定义的cacheNames,那么最后生效的还是方法上自己定义的cacheNames,并不会强行使用类上CacheConfig定义的cacheNames

spring缓存注解redis spring cacheable redis_缓存_10