SpringBoot集成Redis
Redis原生命令大全,作者整理的很详细,大部分命令转化为java命令基本也是关键词
接下来开始我们的正题,一起学习下,SpringBoot整合Redis
引入依赖
pom文件不贴全部代码了,依赖有些多了,占据的篇幅过大,只贴新增的吧
- pom.xml
<!-- 引入redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 引入redis连接池的依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
Redis配置
随着配置越来越多,这里就不贴全部了,注意和datasource
同级,在spring的下级,要去掉spring哈🐾
- 添加application.yml 配置
spring: redis: database: 0 host: 127.0.0.1 port: 6379 timeout: 5000 lettuce: pool: max-active: 32 max-wait: -1 max-idle: 16 min-idle: 8
- 在config包下添加
RedisConfig.java
配置类👇
package com.maple.demo.config; import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author 笑小枫 * @date 2022/07/19 **/ @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); //使用fastjson序列化 FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
工具类
配置完配置,其实我们的Redis就已经集成了,SpringBoot的starter是真的香,后面我们会讲解一下如何制作我们自己的starter。
下面配置一下redis常用的工具类,在util包下创建RedisUtil.java
类👇
package com.maple.demo.util; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Redis常用的一些操作 * * @author 笑小枫 * @date 2022/07/19 */ @Component public class RedisUtil { @Resource private RedisTemplate<String, Object> redisTemplate; /** * 写入缓存 */ public boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<String, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 写入缓存设置时效时间 */ public boolean set(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<String, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 更新缓存 */ public boolean getAndSet(final String key, String value) { boolean result = false; try { redisTemplate.opsForValue().getAndSet(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 批量删除对应的value */ public void remove(final String... keys) { for (String key : keys) { remove(key); } } /** * 批量删除key */ public void removePattern(final String pattern) { Set<String> keys = redisTemplate.keys(pattern); if (CollectionUtils.isNotEmpty(keys)) { redisTemplate.delete(keys); } } /** * 删除对应的value */ public void remove(final String key) { if (exists(key)) { redisTemplate.delete(key); } } /** * 判断缓存中是否有对应的value */ public boolean exists(final String key) { Boolean isExists = redisTemplate.hasKey(key); return BooleanUtils.isTrue(isExists); } /** * 读取缓存 */ public Object get(final String key) { ValueOperations<String, Object> operations = redisTemplate.opsForValue(); return operations.get(key); } /** * 哈希 添加 */ public void hmSet(String key, Object hashKey, Object value) { HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); hash.put(key, hashKey, value); } /** * 哈希获取数据 */ public Object hmGet(String key, Object hashKey) { HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); return hash.get(key, hashKey); } /** * 列表添加 */ public void lPush(String k, Object v) { ListOperations<String, Object> list = redisTemplate.opsForList(); list.rightPush(k, v); } /** * 列表获取 */ public List<Object> lRange(String k, long l, long l1) { ListOperations<String, Object> list = redisTemplate.opsForList(); return list.range(k, l, l1); } /** * 集合添加 */ public void addSet(String key, Object value) { SetOperations<String, Object> set = redisTemplate.opsForSet(); set.add(key, value); } /** * 删除集合下的所有值 */ public void removeSetAll(String key) { SetOperations<String, Object> set = redisTemplate.opsForSet(); Set<Object> objectSet = set.members(key); if (objectSet != null && !objectSet.isEmpty()) { for (Object o : objectSet) { set.remove(key, o); } } } /** * 判断set集合里面是否包含某个元素 */ public Boolean isMember(String key, Object member) { SetOperations<String, Object> set = redisTemplate.opsForSet(); return set.isMember(key, member); } /** * 集合获取 */ public Set<Object> setMembers(String key) { SetOperations<String, Object> set = redisTemplate.opsForSet(); return set.members(key); } /** * 有序集合添加 */ public void zAdd(String key, Object value, double source) { ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); zset.add(key, value, source); } /** * 有序集合获取指定范围的数据 */ public Set<Object> rangeByScore(String key, double source, double source1) { ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet(); return zSet.rangeByScore(key, source, source1); } /** * 有序集合升序获取 */ public Set<Object> range(String key, Long source, Long source1) { ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet(); return zSet.range(key, source, source1); } /** * 有序集合降序获取 */ public Set<Object> reverseRange(String key, Long source, Long source1) { ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet(); return zSet.reverseRange(key, source, source1); } }
测试一下吧
编写我们的测试类
package com.maple.demo.controller; import com.alibaba.fastjson.JSON; import com.maple.demo.util.RedisUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; /** * @author 笑小枫 * @date 2022/7/20 */ @Slf4j @RestController @AllArgsConstructor @RequestMapping("/example") @Api(tags = "实例演示-Redis接口文档") public class TestRedisController { private final RedisUtil redisUtil; @PutMapping("/insertStr") @ApiOperation(value = "插入String类型的数据到redis") public void insertStr(String key, String value) { redisUtil.set(key, value); } @PostMapping("/getStr") @ApiOperation(value = "根据key获取redis的数据") public String getStr(String key) { return String.valueOf(redisUtil.get(key)); } @DeleteMapping("/deleteStr") @ApiOperation(value = "根据key删除redis的数据") public Boolean deleteStr(String key) { redisUtil.remove(key); return redisUtil.exists(key); } @PostMapping("/operateMap") @ApiOperation(value = "模拟操作Map集合的数据") public Object operateMap() { redisUtil.hmSet("maple:map", "xiaofeng", "笑小枫"); return redisUtil.hmGet("maple:map", "xiaofeng"); } @PostMapping("/operateList") @ApiOperation(value = "模拟操作List集合的数据") public String operateList() { String listKey = "maple:list"; redisUtil.lPush(listKey, "小枫"); redisUtil.lPush(listKey, "小明"); redisUtil.lPush(listKey, "小枫"); return JSON.toJSONString(redisUtil.lRange(listKey, 0, 2)); } @PostMapping("/operateSet") @ApiOperation(value = "模拟操作Set集合的数据") public String operateSet() { String listKey = "maple:set"; redisUtil.addSet(listKey, "小枫"); redisUtil.addSet(listKey, "小明"); redisUtil.addSet(listKey, "小枫"); log.info("集合中是否包含小枫" + redisUtil.isMember(listKey, "小枫")); log.info("集合中是否包含小红" + redisUtil.isMember(listKey, "小红")); return JSON.toJSONString(redisUtil.setMembers(listKey)); } @PostMapping("/operateZSet") @ApiOperation(value = "模拟操作ZSet有序集合的数据") public String operateZSet() { String listKey = "maple:zSet"; redisUtil.zAdd(listKey, "小枫", 8); redisUtil.zAdd(listKey, "小明", 1); redisUtil.zAdd(listKey, "小红", 12); redisUtil.zAdd(listKey, "大明", 5); redisUtil.zAdd(listKey, "唐三", 10); redisUtil.zAdd(listKey, "小舞", 9); // 降序获取source最高的5条数据 return JSON.toJSONString(redisUtil.reverseRange(listKey, 0L, 4L)); } }
具体的返回结果我就不一一贴图了,自己建站,流量和网速永远都是一大诟病(哭穷🙈)
简单贴两张吧,怕你们说我敷衍😂😂
- 模拟操作List集合的数据
- 模拟操作ZSet有序集合的数据
监听redis Key过期的事件
- 开始redis过期Key的监听事件
如果数据要求比较严谨,请慎用此功能
修改redis.conf配置为文件,我用的Redis3.2版本(比较古老了😅),windows下是redis.windows-service.conf文件
看一下notify-keyspace-events Ex
是否被注释(默认是注释),放开注释即可。
K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布; E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布; g:一般性的,非特定类型的命令,比如del,expire,rename等; $:字符串特定命令; l:列表特定命令; s:集合特定命令; h:哈希特定命令; z:有序集合特定命令; x:过期事件,当某个键过期并删除时会产生该事件; e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件; A:g$lshzxe的别名,因此”AKE”意味着所有事件。
- 修改我们的
RedisConfig.java
文件,添加开启监听redis Key过期事件,完整配置如下👇
package com.maple.demo.config; import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author 笑小枫 * @date 2022/07/19 **/ @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); //使用fastjson序列化 FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } /** * 开启监听redis Key过期事件 */ @Bean public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory){ RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); return container; } }
- 定义监听器RedisKeyExpireListener
package com.maple.demo.listener; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.stereotype.Component; /** * Redis监听key过期 * * @author 笑小枫 * @date 2022/07/19 **/ @Slf4j @Component public class RedisKeyExpireListener extends KeyExpirationEventMessageListener { public RedisKeyExpireListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } @Override public void onMessage(Message message, byte[] pattern) { String expireKey = message.toString(); // 根据过期的key处理对应的业务逻辑 log.info(expireKey + "已过期-------------------"); } }
小结
好啦,本文就到这里了,我们简单的总结一下,主要介绍了以下内容👇👇
- 本文核心:SpringBoot继承redis
- SpringBoot常用的redis操作演示
- 监听Redis的key过期机制
关于笑小枫💕
本章到这里结束了,喜欢的朋友关注一下我呦😘😘,大伙的支持,就是我坚持写下去的动力。
老规矩,懂了就点赞收藏;不懂就问,日常在线,我会就会回复哈~🤪
笑小枫个人博客:https://www.xiaoxiaofeng.com