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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: spring boot整合redis:http://www.cnblogs.com/sxdcgaq8080/p/8028970.html首先,明确一下问题的场景之前在spring boot整合redis,关于redis的使用都是在repository层上再封装一层service层,在service层上使用的。

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,类名及方法名都是对应的。所以想查看这部分使用的,可以直接在项目中查看即可!!

 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
12天前
|
Java 应用服务中间件 Maven
Spring Boot项目打war包(idea:多种方式)
Spring Boot项目打war包(idea:多种方式)
38 1
|
11天前
|
Java Maven
SpringBoot项目的用maven插件打包报Test错误
SpringBoot项目的用maven插件打包报Test错误
|
3天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的科研项目验收管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的科研项目验收管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
3天前
|
缓存 NoSQL Java
Spring Cache之本地缓存注解@Cacheable,@CachePut,@CacheEvict使用
SpringCache不支持灵活的缓存时间和集群,适合数据量小的单机服务或对一致性要求不高的场景。`@EnableCaching`启用缓存。`@Cacheable`用于缓存方法返回值,`value`指定缓存名称,`key`定义缓存键,可按SpEL编写,`unless`决定是否不缓存空值。当在类上使用时,类内所有方法都支持缓存。`@CachePut`每次执行方法后都会更新缓存,而`@CacheEvict`用于清除缓存,支持按键清除或全部清除。Spring Cache结合Redis可支持集群环境。
31 5
|
3天前
|
NoSQL Java 网络安全
在spring中操作Redis
在spring中操作Redis
19 0
|
4天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的创新创业教育中心项目申报管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的创新创业教育中心项目申报管理系统的设计与实现(源码+lw+部署文档+讲解等)
|
6天前
|
安全 JavaScript Java
装饰工程|装饰工程管理系统-项目立项子系统的设计与实现|基于Springboot的装饰工程管理系统设计与实现(源码+数据库+文档)
装饰工程|装饰工程管理系统-项目立项子系统的设计与实现|基于Springboot的装饰工程管理系统设计与实现(源码+数据库+文档)
14 0
|
10天前
|
前端开发 JavaScript Java
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
|
12天前
|
消息中间件 JSON Java
RabbitMQ的springboot项目集成使用-01
RabbitMQ的springboot项目集成使用-01
|
12天前
|
Java
springboot项目出现Exception in thread “main“ java.lang.NoClassDefFoundError: javax/servlet/Filter
springboot项目出现Exception in thread “main“ java.lang.NoClassDefFoundError: javax/servlet/Filter
19 0