Redis+SpringBoot整合注解版

news/2023/9/27 7:30:29

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项目开发…

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

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

(转) IOS ASI http 框架详解

(转) IOS ASI http 框架详解 ASIHTTPRequest对CFNetwork API进行了封装&#xff0c;并且使用起来非常简单&#xff0c;用Objective-C编写&#xff0c;可以很好的应用在Mac OS X系统和iOS平台的应用程序中。ASIHTTPRequest适用于基本的HTTP请求&#xff0c;和基于REST的服务之间…

Arduino + SmartAirFilter 制作智能感应的 PM 空气净化器

先说 SmartAirFilters 知道 SmartAirFilters 源自微博上转发的非常火的那个帖子&#xff0c;和动辄七八千元的商用产品比&#xff0c;几百元的 SmartAirFilters(下面简称电扇) 确实不贵。一次和朋友在清华科技园里附近的咖啡馆聊天&#xff0c;正好遇见他们在那里做 DIY 体验工…

win10计算机中删除桌面,win10系统电脑桌面壁纸历史记录怎么删除

信任许多win10用户都有过替换电脑桌面壁纸的阅历&#xff0c;并且只需咱们之前有运用过的桌面壁纸都会呈现在个性化界面里&#xff0c;可是有许多win10用户想要将这些运用过的壁纸历史记录删去&#xff0c;那么详细该怎么删去壁纸历史记录呢?今日小编就来为我们介绍win10体系电…

浅谈Java分布式计算

如果所有组件都在同一台计算机的同一个JAVA虚拟机的同一个堆空间上执行是最简单的,但实际中我们面对的往往不是如此单一的情况,如果用户端只是个能够执行Java的装置怎么办&#xff1f;如果为了安全性的理由只能让服务器上的程序存取数据库怎么办? 我们知道,大多数情况下,方法的…

计算机系统化知识,计算机系统基础知识.ppt

您所在位置&#xff1a;网站首页 > 海量文档&nbsp>&nbsp计算机&nbsp>&nbsp计算机原理计算机系统基础知识.ppt62页本文档一共被下载&#xff1a;次,您可全文免费在线阅读后下载本文档。下载提示1.本站不保证该用户上传的文档完整性&#xff0c;不预览…

MyBatis-Plus初次学习

MyBatis-Plus初次学习1、前期的准备工作1.1、依赖1.2、配置1.3、数据库1.4、编写 Entity 类1.5、编写 Mapper 类1.6、启动类上添加 MapperScan 注解1.7、测试2、Mybatis-Plus 常用操作2.1、配置日志2.2、字段名下划线转驼峰2.3、映射mapper.xml和entity文件存放路径2.4、表名下…

【Python】照片居然能变素描?不会画画但是咱会代码

文章目录前言一、准备二、下载预训练模型总结前言 Photo-Sketching 一个能将照片的轮廓识别出来并将其转化为“速写”型图像的开源模块。 比如&#xff0c;这只小狗&#xff1a; 经过模型的转化&#xff0c;会变成卡通版的小狗&#xff1a; 非常秀&#xff0c;这很人工智能…