17. SpringBoot集成Redis(准备篇)
一、前言🔥
相信不少小伙伴在第一篇中已经对redis相关知识点已经有了一定的掌握,加上文末布置的一些常用命令练习,想必基本命令耍起来是么的问题啦。对吧?如果还没掌握的,这肯定不过关啊,必须得强加练习。如今这缓存是现在系统中必不可少的模块,并且已经成为了高并发高性能架构的一个关键组件,所以不会的小伙伴,赶紧学起来啊。
接下里,我要在开篇的基础上,将redis集成到项目里,这一步也很关键,通过代码代替命令执行,比如插入key、删除key、重置key过期时间等,具体使用还得结合具体业务场景进行使用。我一下子说了这么多,肯定有小伙伴吃不定了,脑容量不够啦🐱。
好啦,那我就开始今天的教学啦。
二、集成Redis
1、引入redis依赖
由于springboot也对redis进行过集成,在springboot下有spring-boot-starter-data-redis,那我们索性就直接拿来用吧。在你的pom.xml中引入如下依赖,使用Redis就相当的简单了。
<!--集成redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.4.5</version>
</dependency>
2、配置.yaml配置文件
引入依赖后,我们就要在我们的配置文件中,指定redis服务等相关信息了。
你们可以参考我如下配置,先把如下redis配置先加入到你的application-xxx.yaml中,然后再配置你redis服务器的ip、端口、密码等信息,ip、密码等信息必须和你的服务器一致。如果是有小伙伴用的是.properties格式的配置文件,也一样,将语法转一下即可哈。我们就以.yaml文件格式配置进行演示。
application-test.yaml
#redis配置
spring:
redis:
database: 0 #redis数据库索引(默认为0)
host: 127.0.0.1 #redis服务器ip,由于我是搭建在本地,固指向本地ip
port: 6379 #redis服务器连接端口
password: #redis服务器连接密码(默认为空)
# 连接池配置
jedis.pool:
max-active: 20 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
timeout: 1000 #连接超时时间(毫秒)。我设置的是1秒
小伙伴可能就会问了:“以上配置完了,怎么测试项目是否能与redis服务连通呢?”
问的好,其实也很简单,我们一步一步来,测试通与不通,待会儿只需要写个test-case执行一下任意一个redis操作不就清楚到底这个配置对不对,好吧?
3、配置redis-config
当我们的数据存储到Redis的时候,我们的key/value都是通过Spring提供的Serializer序列化到数据库的,而RedisTemplate默认使用的是JdkSerializationRedisSerializer。我们再说下StringRedisTemplate,该方法继承了RedisTemplate,确定了Key/Value类型为String类型,并且实现了两个构造器。所以我们接下来就改用StringRedisSerializer来序列化数据库。
大家按我如下配置即可:
package com.example.demo.config;
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.StringRedisTemplate;
/**
* redis配置类
*
* @Author luoYong
* @Date 2022-01-20 17:29
*/
@Configuration@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {
/**
* 字符串Template
*
* @param connection redis连接
*/
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connection) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(connection);
return template;
}
}
- 使用时注意事项:
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。
- RedisTemplate使用时常见问题:
redisTemplate 中存取数据都是字节数组。当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null。可以使用 StringRedisTemplate 试试。
... ...
以上两点都是我实际开发项目中踩过的坑,希望你们届时玩它的时候,都注意一下啦。
4、封装redis中介类
RedisMediator.java,用于从redis中读取内容或更新数据。如果需要别的,也都可以往里加。
package com.example.demo.component.redis;
import com.example.demo.util.JsonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Redis中介类,用于从redis中读取内容或者更新数据
*
* @Author luoYong
* @Date 2022-01-20 17:47
*/
@Slf4j
@Component
public class RedisMediator {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Value("${luoyong.redis.login-time-out:1800}")
private Integer timeOut;
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
*/
public void set(String key, String value) {
set(key, value, timeOut);
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值 String
* @param time 过期时间
*/
public void set(String key, String value, long time) {
this.checkKey(key);
stringRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}
/**
* 普通缓存获取
*
* @param key 键
*/
public String get(String key) {
this.checkKey(key);
return stringRedisTemplate.opsForValue().get(key);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
this.checkKey(key);
return stringRedisTemplate.hasKey(key);
}
/**
* 删除缓存
*
* @param key 健
*/
public void del(String key) {
this.checkKey(key);
stringRedisTemplate.delete(key);
}
/**
* 刷新缓存时间
*
* @param key
*/
public Boolean expire(String key) {
return this.expire(key, timeOut);
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public Boolean expire(String key, long time) {
return stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
}
/**
* 检查key是否为空
*
* @param key 健
*/
private void checkKey(String key) {
if (StringUtils.isBlank(key)) {
throw new RuntimeException("redis key不能为空");
}
}
}
5、test-case测试
redis配置也好了,工具类也刚码完,接下来,就下来就是验证这一切准备工作是否成功的关键一环了,那就是进行test-case测试类测试,如果读写都一切正常,那就说明redis集成是成功的,剩下的我也就不跟大家一一絮叨了。
首先我们来测试第一个,如何redis写入一个key:value。
a、插入一个key
/**
* 插入一个key
*/
@Testvoid testSetKey() {
redisMediator.set("name", "diaochan");
}
redis客户端,根据key查一下,验证是否插入成功。
请看如下截图,明显是插入成功啦。此刻也还说明一件事,证明redis集成到项目中,项目与redis服务是连通的,证明我们刚才配置的redis信息,都是没有问题的,这下大家可以放心了,尽管拿去,然后改成自己的redis配置就可以了。
b、从redis获取一个key的值
这一步你可以去控制台自己根据key获取,也可以像我这样,通过代码调用的方式来获取。但是我们是在测试代码与redis相通,所以最好是以代码的方式来代替redis命令。
@Testvoid testGetKey() {
String name = redisMediator.get("name");
System.out.println("获取到的name对于的值为:" + name);
}
c、指定某个key的缓存失效时间(秒)
这一步其实是这样的,存入redis中,如果没有指定key的过期时间,那该key便永久存在于你的redis中,但不排除你开启了redis定时删除key的策略。所以我们在插入一个key的时候,是提供了一个参数,给你们进行设置的set(String key, String value, long time)
其中long time就是指定该key的过期时间的,单位为秒。这个大家需要注意一下,在插入的时候,切记把过期时间也设置进去哦。
@Test
void testExpireKey() {
redisMediator.expire("name", 3600);
}
如下图:
d、删除一个key
@Test
void testDelKey() {
redisMediator.del("name");
}