Redis+SpringBoot整合注解版

news/2024/6/20 2:15:43

Redis+SpringBoot整合注解版

  • 一、前言
  • 二、配置文件
    • 1.导入redis依赖
    • 2.application.properties的配置
    • 3.创建RedisConfig
  • 三、使用注解开发
  • 四、测试
  • 五、其他


一、前言

我的上一篇博客是无注解版,围绕着RedisTemplate方法进行展开。
我的观点是注解简单但是不适合业务复杂的项目。
链接地址


二、配置文件

1.导入redis依赖

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

2.application.properties的配置

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000

3.创建RedisConfig

注:RedisConfig类用于Redis数据缓存。

/*** redis配置类**/
@Configuration
@EnableCaching//开启注解式缓存
//继承CachingConfigurerSupport,为了自定义生成KEY的策略。可以不继承。
public class RedisConfig extends CachingConfigurerSupport {/*** 生成key的策略 根据类名+方法名+所有参数的值生成唯一的一个key** @return*/@Bean@Overridepublic KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder sb = new StringBuilder();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}/*** 管理缓存** @param redisConnectionFactory* @return*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {//通过Spring提供的RedisCacheConfiguration类,构造一个自己的redis配置类,从该配置类中可以设置一些初始化的缓存命名空间// 及对应的默认过期时间等属性,再利用RedisCacheManager中的builder.build()的方式生成cacheManager:RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();  // 生成一个默认配置,通过config对象即可对缓存进行自定义配置config = config.entryTtl(Duration.ofMinutes(1))     // 设置缓存的默认过期时间,也是使用Duration设置.disableCachingNullValues();     // 不缓存空值// 设置一个初始化的缓存空间set集合Set<String> cacheNames = new HashSet<>();cacheNames.add("my-redis-cache1");cacheNames.add("my-redis-cache2");// 对每个缓存空间应用不同的配置Map<String, RedisCacheConfiguration> configMap = new HashMap<>();configMap.put("my-redis-cache1", config);configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120)));RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)     // 使用自定义的缓存配置初始化一个cacheManager.initialCacheNames(cacheNames)  // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置.withInitialCacheConfigurations(configMap).build();return cacheManager;}@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);serializer.setObjectMapper(mapper);template.setValueSerializer(serializer);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.afterPropertiesSet();return template;}@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();stringRedisTemplate.setConnectionFactory(factory);return stringRedisTemplate;}}

注意:
继承CachingConfigurerSupport,为了自定义生成KEY的策略。可以不继承。
RedisConfig entends CachingConfigurerSupport

在CacheManager中我在这里添加了两个缓存槽:my-redis-cache1和my-redis-cache2。

三、使用注解开发

@Cacheable
作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

    //添加到缓存@Override@Cacheable(value="my-redis-cache1",key = "'getUser'+#name",condition="#name=='yuange'")public User getUser(String name) {User user = new User();user.setName(name);return user;}

参数说明:

value :
缓存的名称,在 spring 配置文件中定义,必须指定至少一个,

key :缓存的 key,可以为空,
如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,
例如:@Cacheable(value=”my-redis-cache1”,key=”#name”)。

condition :缓存的条件,可以为空,
使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存,
例如: @Cacheable(value=“my-redis-cache1”,key = “‘getUser’+#name”,condition=“#name==‘yuange’”)


@CachePut
只存不读 每次都真实查询数据库,把数据带到内存来;
作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实 方法的调用

    //修改缓存值@Override@CachePut(value = "my-redis-cache1", key = "'getUser'+#name")public User updateUser(String name) {User user = new User();user.setName(name);System.out.println("修改了名字");return user;}

主要参数说明:
@Cacheable一样。


@CacheEvict:
作用是主要针对方法配置,能够根据一定的条件对缓存进行清空

    //删除缓存值@Override@CacheEvict(value = "my-redis-cache1", key = "'getUser'+#name")public void delUser(String name) {System.out.println("清除完成");}

参数说明:
allEntries :
是否清空所有缓存内容,缺省为 false,
如果指定为 true,则方法调用后将立即清空所有缓存,
例如:@CacheEvict(value=”testcache”,allEntries=true)。

beforeInvocation :
是否在方法执行前就清空,缺省为 false,
如果指定为 true,则在方法还没有执行的时候就清空缓存,
缺省情况下,如果方法执行抛出异常,则不会清空缓存,
例如@CacheEvict(value=”testcache”,beforeInvocation=true)。


四、测试

实体类User

/*** @author lichangyuan* @create 2021-02-22 22:20*/
public class User implements Serializable{private String name;public User() {System.out.println("创建了对象");}public User(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}

UserServiceImpl

/*** @author lichangyuan* @create 2021-02-22 23:43*/
@Service
public class UserServiceImpl implements UserService {//添加到缓存@Override@Cacheable(value="my-redis-cache1",key = "'getUser'+#name",condition="#name>10")
//    @Cacheable(value = "my-redis-cache1", key = "'getUser'+#name")public User getUser(String name) {User user = new User();user.setName(name);return user;}//修改缓存值@Override@CachePut(value = "my-redis-cache1", key = "'getUser'+#name")public User updateUser(String name) {User user = new User();user.setName(name);System.out.println("修改了名字");return user;}//删除缓存值@Override@CacheEvict(value = "my-redis-cache1", key = "'getUser'+#name")public void delUser(String name) {System.out.println("清除完成");}@Override@CacheEvict(value = "my-redis-cache1", allEntries = true)public void clear() {System.out.println("my-redis-cache1清除成功");}@Override@CacheEvict(value = "my-redis-cache1", allEntries = true)public void clear2() {System.out.println("my-redis-cache1清除成功");}}

UserController

/*** @author lichangyuan* @create 2021-02-22 23:41*/
@RestController
public class UserController {@AutowiredUserService userService;@RequestMapping("get_name")public void getName(@RequestParam("name") String name) {//第一次获取假设是从数据库获取,并写入缓存User user = userService.getUser(name);//第二次获取由于缓存中已存在所以从缓存中获取User user2 = userService.getUser(name);System.out.println("===============================================");//更改缓存内容,因此不会读缓存会调用无参构造器创建一次对象。User user3 = userService.updateUser(name);System.out.println("===============================================");//删除指定缓存nameuserService.delUser(name);//因为缓存中的值被我们删掉了,再获取时又会创建一次对象而不是从缓存中拿User user4 = userService.getUser(name);}
}

使用postman测试
测试样例
测试结果

测试结果


五、其他

@Cacheable注解不生效原因

一个方法A调同一个类里的另一个有缓存注解的方法B,这样是不走缓存的。
例如在同一个service里面两个方法的调用,缓存是不生效的;
解决方案:

1.不使用注解的方式,直接取 Ehcache 的 CacheManger 对象,把需要缓存的数据放到里面,类似于使用 Map,缓存的逻辑自己控制;或者可以使用redis的缓存方式去添加缓存;

2.把方法A和方法B放到两个不同的类里面,例如:如果两个方法都在同一个service接口里,把方法B放到另一个service里面,这样在A方法里调B方法,就可以使用B方法的缓存。


为什么缓存没有被正常创建?

因为@Cacheable 是使用AOP 代理实现的 ,通过创建内部类来代理缓存方法,这样就会导致一个问题,类内部的方法调用类内部的缓存方法不会走代理,不会走代理,就不能正常创建缓存,所以每次都需要去调用数据库。


@Cacheable是想缓存中添加数据,
@CachePut 更新缓存中的数据,
@CacheEvict是删除缓存中的数据

  • 希望2022变得好—点,再好—点。冲鸭!
  • 希望我俩能走出困境,家庭美满幸福。
  • 我有两个愿望,你在身边,在你身边。
  • 晴天、雨天、阴天,愿你快乐每一天。
  • 愿望不是许出来的,是自己努力换来的!
  • 点亮一—盏心灯,点亮爱,烛照光明前路!
  • 万家灯火,千里祈福,愿一切越来越好。
  • 你的离别已是蓄谋已久,又何必找借口。
  • 愿你遇良人,予你欢喜城,长歌暖浮生。
  • 愿您:大财、小财、意外财,财源滚滚。

https://dhexx.cn/news/show-18518.html

相关文章

ios使用zxing

ZXing( Github镜像地址)是一个开源的条码生成和扫描库&#xff08;开源协议为 Apache2.0)。它不但支持众多的条码格式&#xff0c;而且有各种语言的实现版本&#xff0c;它支持的语言包括&#xff1a;Java、 C、 C#、 Objective-C、ActionScript以及Ruby。 我以前在iOS项目开发…

计算机考数学一英语二的学校,【专硕】初试考数学一的学校统计

考研倒计时113天应小伙伴需求&#xff0c;整理汇总了专硕初试考数学一的学校。本文信息内容来自公众号计算机考研说每天推送的【院校信息】&#xff0c;从140所院校信息筛选出&#xff0c;原谅小编没有从所有学校中筛选..若有错误或者遗漏&#xff0c;欢迎在下方留言指正补充~北…

快排 + 二分

0)注销M Time Limit: 1000ms Memory limit: 65536K 有疑问&#xff1f;点这里^_^ 题目描述 给出含有n个数的升序序列&#xff0c;保证序列中的数两两不相等&#xff0c;这n个数编号从1 到n。然后给出q次询问&#xff0c;每次询问给出一个数x&#xff0c;若x存在于此序列中&a…

Spring boot项目长时间不进行接口操作,解决HikariPool-1提示

Spring boot项目长时间不进行接口操作&#xff0c;解决HikariPool-1提示问题描述一、解决方法总结问题描述 Springboot项目长时间没运行我运行的时候一直报错&#xff0c;导致接口调用失败 2021-02-23 18:13:23.044 WARN 13564 --- [nio-8088-exec-7] com.zaxxer.hikari.poo…

C# Dictionarykey,value (转)

简介在C#中,Dictionary提供快速的基于兼职的元素查找。当你有很多元素的时候可以使用它。它包含在System.Collections.Generic名空间中。 在使用前&#xff0c;你必须声明它的键类型和值类型。 详细说明必须包含名空间System.Collection.Generic Dictionary里面的每一个元素都是…

excel C# 报表制作汇总

http://blog.csdn.net/aaaaatiger/article/details/4627176转载于:https://www.cnblogs.com/tianshuilv/p/3761183.html

speak 计算机英语作文,实用的学英语作文5篇

实用的学英语作文5篇在日常学习、工作抑或是生活中&#xff0c;大家都写过作文&#xff0c;肯定对各类作文都很熟悉吧&#xff0c;借助作文可以宣泄心中的情感&#xff0c;调节自己的心情。还是对作文一筹莫展吗&#xff1f;以下是小编为大家收集的学英语作文5篇&#xff0c;仅…

redis 基本概述 [文档]

讲到redis不得不讲nosql NoSQL是不同于传统的关系数据库的数据库管理系统的统称。其两者最重要的区别是NoSQL不使用 SQL作为查询语言。 NoSQL数据存储可以不需要固定的表格模式。NoSQL是基于键值对的&#xff0c;可以想象 成表中的主键和值的对应关系。 NoSQL&#xff1a;redi…

Springboot项目打包错误提示maven-resources-plugin:3.2.0:resources (default-resources) @ 07-springboot-session

Springboot项目打包错误提示错误信息如下 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) 07-springboot-session --- [INFO] Using UTF-8 encoding to …