SpringBoot集成Redis
Redis原生命令大全,作者整理的很详细,大部分命令转化为java命令基本也是关键词
Redis 命令参考
接下来开始我们的正题,一起学习下,SpringBoot整合Redis
引入依赖
pom文件不贴全部代码了,依赖有些多了,占据的篇幅过大,只贴新增的吧
-
pom.xml
org.springframework.boot spring-boot-starter-data-redisorg.apache.commons commons-pool2
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
工具类
配置完配置,其实我们的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 redisTemplate;
/**
* 写入缓存
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations 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 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 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 operations = redisTemplate.opsForValue();
return operations.get(key);
}
/**
* 哈希 添加
*/
public void hmSet(String key, Object hashKey, Object value) {
HashOperations hash = redisTemplate.opsForHash();
hash.put(key, hashKey, value);
}
/**
* 哈希获取数据
*/
public Object hmGet(String key, Object hashKey) {
HashOperations hash = redisTemplate.opsForHash();
return hash.get(key, hashKey);
}
/**
* 列表添加
*/
public void lPush(String k, Object v) {
ListOperations list = redisTemplate.opsForList();
list.rightPush(k, v);
}
/**
* 列表获取
*/
public List lRange(String k, long l, long l1) {
ListOperations list = redisTemplate.opsForList();
return list.range(k, l, l1);
}
/**
* 集合添加
*/
public void addSet(String key, Object value) {
SetOperations set = redisTemplate.opsForSet();
set.add(key, value);
}
/**
* 删除集合下的所有值
*/
public void removeSetAll(String key) {
SetOperations set = redisTemplate.opsForSet();
Set 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 set = redisTemplate.opsForSet();
return set.isMember(key, member);
}
/**
* 集合获取
*/
public Set setMembers(String key) {
SetOperations set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
*/
public void zAdd(String key, Object value, double source) {
ZSetOperations zset = redisTemplate.opsForZSet();
zset.add(key, value, source);
}
/**
* 有序集合获取指定范围的数据
*/
public Set rangeByScore(String key, double source, double source1) {
ZSetOperations zSet = redisTemplate.opsForZSet();
return zSet.rangeByScore(key, source, source1);
}
/**
* 有序集合升序获取
*/
public Set range(String key, Long source, Long source1) {
ZSetOperations zSet = redisTemplate.opsForZSet();
return zSet.range(key, source, source1);
}
/**
* 有序集合降序获取
*/
public Set reverseRange(String key, Long source, Long source1) {
ZSetOperations 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@__为前缀进行发布;
E:keyevent事件,事件以__keyevent@__为前缀进行发布;
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 redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate template = new RedisTemplate();
//使用fastjson序列化
FastJsonRedisSerializer 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
CSDN:https://zhangfz.blog.csdn.net
本文源码:https://github.com/hack-feng/maple-demo
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net