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

 

时间: 2024-10-03 01:18:26

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

在Spring Boot项目中使用Spock框架

Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring Boot项目中使用该框架写优雅.高效以及DSL化的测试用例.Spock通过@RunWith注解与JUnit框架协同使用,另外,Spock也可以和Mockito(Spring Boot应用的测试--Mockito)协同使用. 在这个小节中我们会利用Spock.Mockito一起编写一些测试用例(包括对Controller的测试和对Repository的测试),感受下Spock的使用.

spring boot项目中处理Schedule定时任务

默认,springboot已经支持了定时任务Schedule模块,所以一般情况已经完全能够满足我们的实际需求,一般来说,没有必要在加入其他类似于:quartz 另外,在这里提一个实际项目中,关于定时任务的架构上的一些考虑: 一般来说,实际项目中,为了提高服务的响应能力,我们一般会通过负载均衡的方式,或者反向代理多个节点的方式来进行.通俗点来说,我们一般会将项目部署多实例,或者说部署多份,每个实例不同的启动端口.但是每个实例的代码其实都是一样的.如果我们将定时任务写在我们的项目中,就会面临一个麻烦

Spring Boot 项目构建 之 使用 Spring Boot 构建应用(Building an Application with Spring Boot)

Table of contents What you'll build What you'll need How to complete this guide Build with Gradle Build with Maven Build with Spring Tool Suite Learn what you can do with Spring Boot Create a simple web application Create an Application class Run the

spring boot项目中使用jpa的一个未解之谜

公司最近主要的工作就是把之前的一个项目进行几乎全面的重构,之所以说几乎全面,是因为除开业务逻辑外全部换血: 框架由spring+struts2+mybatis改为spring boot+jpa 数据库由sybase+h2改为oracle+redis 子系统之间的交互由activemq改为http 代码具体实现全部重写 对一个运行了若干年的项目进行这样的大动作,路程无疑是漫长而复杂的.在进行了一系列设计文档的编写.评审.修订.再评审之后,终于可以开始码代码了. 本以为码代码终于可以松一口气,没想到

struts2改spring boot过程中一些问题及解决办法记录

1.引入依赖包的问题 一般情况下,常用的jar包在maven仓库都可以找到,并能知道如何在pom.xml文件中配置,但是有时候需要在一些项目中使用一些我们自己写的代码生成的jar包,要引入maven中就需要做一些必要的处理. 我们项目中就有这样的情况存在,以下是处理方式之一,就是用maven的命令生成maven方式的jar,然后加入到本地库中引用,打包命令如下: mvn install:install-file -Dfile=huateng-comm-1.0.0.jar -DgroupId=co

requirejs在spring boot程序中路径配置问题

问题描述 requirejs在spring boot程序中路径配置问题 我想使用resources目录下的js文件,但是它是从webapp目录下找的,所以每次都是404错误, require(["/public/js/delete"]); 请教大家要怎么解决?

项目中使用到spring,关于性能问题

问题描述 项目中使用到spring注入一个个对象,在项目启动的时候,会加载实例化所有配置的对象,请问这些对象被实例化后,会大量占用内存吗?最近项目启动后,在运行过程中,发现所占用的内存是一直在不停地增加的.寻找测试内存不停上升的方法,谢谢各位! 解决方案 解决方案二:我感觉用spring的话,注入对象不要太多,一般就是注入持久层相关的对象(dao.hibernateTemplate.事务)实体对象我都是手动new的.

线程-spring+netty项目中使用NIO的技术

问题描述 spring+netty项目中使用NIO的技术 在做一个springmvc+netty的项目,要求当请求进到方法正常返回一个成功的同时另一条线程处理后台的业务,后台业务在处理的同时其实这个会话已经正常返回了. @RequestMapping(value = "/static/o_index.do",method={RequestMethod.POST,RequestMethod.GET}) public void indexSubmit(HttpServletRequest

为什么XML规范中说元素标记名不能用xml字符开头,但是我用xml字符开头也不报错?

问题描述 为什么XML规范中说元素标记名不能用xml字符开头,但是我用xml字符开头也不报错? 为什么XML规范中说元素标记名不能用xml字符开头,但是我用xml字符开头也不报错?比如:为什么浏览器打开不报错? 解决方案 没有这个规定啊.可以用xml开头作为标签 解决方案二: 可能是为了数据兼容什么增加的规范吧.浏览器支持就行,就如你加了xhtml申明,一些不支持的标签你html页面有浏览器还是会支持.标签不闭合也不会报错显示不友好什么的