• 【redis】5.spring boot项目中,直接在spring data jpa的Repository层使用redis +redis注解@Cacheable直接在Repository层使用,报错问题处理Null key returned for cache operation


    spring boot整合redis:http://www.cnblogs.com/sxdcgaq8080/p/8028970.html

    首先,明确一下问题的场景

    之前在spring boot整合redis,关于redis的使用都是在repository层上再封装一层service层,在service层上使用的。

    现在如果直接将redis的注解放在repository上使用,是个什么情况呢?

    代码如下:

      1.首先我有一个实体XxAdmin,主键为id

      2.Xxadmin我写了一个AdminRepository

    package com.agen.myagen.repository;
    
    
    import com.agen.myagen.entity.XxAdmin;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    
    /**
     * admin持久化层
     *
     * @author SXD
     * @date 2017/12/26
     */
    public interface AdminRepository extends JpaRepository<XxAdmin,Integer> {
    
        /**
         * 查找机构信息
         * 并缓存到redis,键为id  值为XxAdmin
         * @param adminId
         * @return
         */
        @Cacheable(value="admins", key="#adminId")
        @Override
        XxAdmin findOne(Integer adminId);
    }
    View Code

      3.我在controller直接调用

    package com.agen.controller;
    
    
    import com.agen.myagen.entity.XxAdmin;
    import com.agen.myagen.repository.AdminRepository;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.annotation.Resource;
    
    
    @Controller
    public class MainController {
    
        @Resource
        private AdminRepository adminRepository;
    
        @RequestMapping("index")
        public String getOrder(String adminId){
            Integer adminID = Integer.parseInt(adminId);
            XxAdmin admin = adminRepository.findOne(adminID);
            return  null;
        }
    
    
    }
    View Code

    【报错】 

    启动之后,报错如下:Null key returned for cache operation (maybe you are using named params on classes without debug info?)

    java.lang.IllegalArgumentException: Null key returned for cache operation (maybe you are using named params on classes without debug info?) Builder[public abstract com.agen.myagen.entity.XxAdmin com.agen.myagen.repository.AdminRepository.findOne(java.lang.Integer)] caches=[admins] | key='#adminId' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'

    报这个错,原因就是redis认定这个key是Null的,没办法存入,所以报错了。

    但是之前咱们上一篇就是这么用的呀,查看上一篇,可以发现,redis是使用在service层,是在repository的再封装层使用的,那redis就不能直接使用在repository层了么?

    【这里因为项目原因,不赘述为什么不封装一层service层使用,而是直接在repository层使用】【最后具体为什么key在这里会认定为null也没有找到原因,若知情,恳请告知!!!谢谢了】

    【解决方法】

    翻来覆去之后,发现redis的@Cacheable注解放在repository方法上,key会被认定为null,导致存不进redis缓存。

    所以,换一种思路来解决这个问题,就是提前设定一种key的生成策略,即在RedisConfig类中指定一种KeyGenerator。【这一步骤的解释,可以查看http://www.cnblogs.com/sxdcgaq8080/p/8028970.html

    具体的解决方法如下:

      在RedisConfig中,设定仅取第一个参数作为key的key生成策略

    /**
         * 生成key的策略【自定义第三种】
         * 使用范围:仅适用于选取第一个参数做键的情况
         * 由于reposotory上不能直接使用spel表达式作key,故而采用key的生成策略的方式来替换
         *
         * 使用时在注解@Cacheable(value = "admins",keyGenerator = "firstParamKeyGenerator")中指定
         * @return
         */
        @Bean(name = "firstParamKeyGenerator")
        public KeyGenerator firstParamKeyGenerator(){
            return new KeyGenerator() {
                @Override
                public Object generate(Object target, Method method, Object... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(params[0].toString());
                    return sb.toString();
                }
            };
        }
    View Code

    然后在AdminRepository中更换@Cacheable中的属性

    public interface AdminRepository extends JpaRepository<XxAdmin,Integer> {
    
        /**
         * 查找机构信息
         * 并缓存到redis,键为id  值为XxAdmin
         * @param adminId
         * @return
         */
        @Cacheable(value="admins", keyGenerator = "firstParamKeyGenerator")
        @Override
        XxAdmin findOne(Integer adminId);
    }
    View Code

    然后再去访问一次,

    控制台成功从数据库查询了Xxadmin对象

    查看redis中,已经将本对象存入缓存

    再次访问,发现并未执行SQL语句,直接从缓存中取出本对象。

    OK,直接在spring boot的repository层使用redis注解成功。

    ==============================================================================================================================================

    最后,可以将AdminRepository类上使用

    @CacheConfig(cacheNames = "admins")

    指定本类中所有的方法,操作的缓存都是名为admins的缓存!!

    package com.agen.myagen.repository;
    
    
    import com.agen.myagen.entity.XxAdmin;
    import org.springframework.cache.annotation.CacheConfig;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    
    /**
     * admin持久化层
     *
     * @author SXD
     * @date 2017/12/26
     */
    @CacheConfig(cacheNames = "admins")
    public interface AdminRepository extends JpaRepository<XxAdmin,Integer> {
    
        /**
         * 查找机构信息
         * 并缓存到redis,键为id  值为XxAdmin
         * @param adminId
         * @return
         */
        @Cacheable(keyGenerator = "firstParamKeyGenerator")
        @Override
        XxAdmin findOne(Integer adminId);
    }
    View Code

    具体可以参考:http://www.cnblogs.com/sxdcgaq8080/p/7228163.html查看这几个注解的使用场景

    ==============================================================================================================================================

    本系列的源代码,可以从GitHub上获取查看:https://github.com/AngelSXD/myagenorderdiscount,类名及方法名都是对应的。所以想查看这部分使用的,可以直接在项目中查看即可!!

  • 相关阅读:
    触发器
    dubbox 及 zookeeper的安装与启动
    负载均衡
    SOA架构
    获取短信验证码
    分步式
    saoruo
    Ngx
    redies技术
    Springboot开发特点
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/8119081.html
Copyright © 2020-2023  润新知