Spring Cache常见问题解决

目录

[一 报错:Null key returned for cache operation](#一 报错:Null key returned for cache operation)

[二 报错:类型转换异常](#二 报错:类型转换异常)

[三 取出的数据为null](#三 取出的数据为null)


一 报错:Null key returned for cache operation

这里报错有两种情况:

第一,如果你在新增的方法上使用Cacheable注解,那么肯定是会报这个错误的。

因为Cacheable注解的原理是先根据key去Redis查看有没有这个缓存数据 , 如果没有在保存。

那么问题就出现了 , 我们传入的新增的参数肯定是不会带有主键id的,那么此时他根据id去查找key,而你的id是null,他就会报这个错误。

解决办法:

换成CachePut注解,因为这个注解不会先去查找,而是直接添加到缓存中,所以就不存在这个情况。

第二,使用的是CachePut,但还是报这个错误。

这个情况,肯定是因为你使用的是xxxDTO来接收前端的参数,而不是直接使用xxx的实体类来接受,这样就导致一个问题,就是前端传来的参数主键id肯定一开始也是null , 二主键的回显是在调用的mapper层之后才生成的,而错就错在,你是用xxx实体类对象来接收回显的主键,而不是xxxDTO这个参数对象,那么当整个方法执行完后,xxxDTO这个参数的id一直都是null,而注解是这样的:

复制代码
@CachePut(cacheNames = "dishCache" , key = "#dishDTO.id")

他是根据xxxDTO来获取id的,所以会报key为null。

解决办法:

当然,我们肯定不能直接换成实体类来接收前端传来的参数,因为毕竟可能有些属性实体类没有需要我们使用xxxDTO来接收。所以我们可以在主键回显后, 把主键赋值给xxxDTO就可以了,具体代码如下:

复制代码
     /*
            为什么这里要多此一举给参数dishDTO赋值id呢?因为上面在使用springCache需要从dishDTO获取id生成key,
            但是dishDTO中的参数在这个方法执行完一直都是null , 主键回显只会回显在dish对象中的id。
            所以springCache得不到id就会报错 , 所以需要给dishDTO的id赋值。
         */
        dishDTO.setId(dish.getId());

二 报错:类型转换异常

这个问题一定是因为你存入数据的注解和取出数据的注解放在不一样的层的方法上。

最常见的是,你把CachePut方法放在Controller层的方法上,那么你存入的数据肯定是一个Result类型的数据。而你把Cacheable注解方法Server层方法上,那么该方法返回的肯定是一个xxx实体类,这就会导致,你存入的数据是一个Result类,而你需要取的数据又变成了xxx实体类,从而导致报错。

解决办法:

你可以全部放在Server层,或者全部放在Controller,只要确保你存入数据的方法的返回数据类型和你取出方法的返回数据类型一致就可以。

三 取出的数据为null

这个不用看,一定是因为你存入缓存的注解放在了一个返回为void的方法上面。

你只需要记住,springCache的注解,他的存入和取出的数据的类型一定是根据你的方法的返回值来的。如果你的返回值类型是void,那么他存入缓存的数据就是null,所以你取出来肯定也是null。

演示代码如下;

java 复制代码
 @CachePut(cacheNames = "dishCache" , key = "#dishDTO.id")
    @Override
    public void addDish(DishDTO dishDTO) {
//        向菜品表插入数据
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO , dish);
        dishMapper.addDish(dish);
//        因为下面的菜品口味表需要使用到菜品的id,所以这里菜品完成后,需要获取菜品id,再赋值给菜品口味
        Long dishId = dish.getId(); //但是这个id不能直接得到,需要在sql中使用主键回显,才能把生成的主键返回

        /*再根据菜品id,新增菜品口味表*/
//        取出集合数据
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors!=null && flavors.size()>0){
//            这里需要遍历集合中每一个dishFlavor对象,把dishId赋值给他们
            flavors.forEach(dishFlavor -> {dishFlavor.setDishId(dishId);});
            dishFlavorMapper.addDishFlavor(flavors) ;
        }

        /*
            为什么这里要多此一举给参数dishDTO赋值id呢?因为上面在使用springCache需要从dishDTO获取id生成key,
            但是dishDTO中的参数在这个方法执行完一直都是null , 主键回显只会回显在dish对象中的id。
            所以springCache得不到id就会报错 , 所以需要给dishDTO的id赋值。
         */
        dishDTO.setId(dish.getId());
    }

取出的值如下:

解决方法:

把方法的返回值类型由viod改成对应的需要存储的数据的实体类型。

相关推荐
IT大白鼠4 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz4 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
lbb 小魔仙5 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
夕除5 天前
redis--018
redis
两锭子5 天前
Redis基础
redis
烟沙九洲5 天前
Redis 缓存穿透、缓存击穿、缓存雪崩
数据库·redis
字节探索5 天前
Redis 只会当缓存用?这 10 大实战场景,让你的系统快到飞起
redis·后端
于樱花森上飞舞5 天前
【Redis】哨兵详解
java·开发语言·数据库·redis
Rain的Java大神之路5 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog5 天前
Java 接入Redis: 通用命令与键管理
java·服务器·redis