SpringBoot整合Redis
最近在学习redis,把redis单机数据库的基础知识看的差不多了,准备用SpringBoot整合实践一下。
最开始去看spring官网关于spring-data-redis的文档(英文不太好,结合有道看了几个重点的地方,但是上面也没有具体说到
这个代码该怎么写)。
然后百度了几篇博文,都看了一遍,大致理清网上作者们的思路。关于SpringBoot整合redis的文章一般有这么这种:
- 直接引入redis-client的客户端来使用的。
- 引入spring-boot-starter-data-redis来使用的(这是Spring推荐的方式,帮助我们封装了redis-client)。
- 关于Spring Cache和redis做整合的。
第三种可以暂时不关注它,第三种的使用应该建立在先会第一种或者第二种通过代码手动的去操作redis的基础上。
第一种是直接使用redis-client,在Spring的项目中不推荐使用这种方式,因为redis的客户端实在太多了,各个客户端的语法可能
不太一样,不利于后期更换客户端。
以下是用Java实现的Redis客户端
可以看到,光Java的客户端就有这么多。Redis官方推荐的有Jedis、Lettuce和Redisson。
而第二种就是今天要讲的,Spring帮我们封装了Lettuce和Jedis两种客户端,并为开发者提供了更高级的一些API。
下面开始整合(关于SpringBoot和Redis我就假设各位读者大人都是已知的)
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redis依赖commons-pool 这个依赖一定要添加 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
这里要说明一下,我之前在网上看了一些文章的依赖是spring-boot-starter-redis,这是老版本的。另外需要注意的是2.x版本以前的
Redis客户端默认是用Jedis来实现的,而在2.x版本则是用Lettuce来实现的,所以在配置上面有所不同。
SpringBoot配置文件
1 server: 2 port: 80 3 spring: 4 cache: 5 type: 6 redis 7 redis: 8 host: l27.0.0.1 9 port: 6379 10 # 密码,如果没有设置可以不填写,设置密码请看redis.conf的requirepass参数 11 password: 123456 12 # 如果使用的jedis 则将lettuce改成jedis即可 13 lettuce: 14 pool: 15 # 最大活跃链接数 默认8 16 max-active: 8 17 # 最大空闲连接数 默认8 18 max-idle: 8 19 # 最小空闲连接数 默认0 20 min-idle: 0
Spring Data Redis为我们提供一个对象redisTemplate用于操作redis,下面是它的源码
Spring默认为我们实现了两个对象redisTemplate和stringRedisTemplate,其中stringRedisTemplate是专门用来操作字符对象的,因为在实际使用中,
用Redis来缓存字符串对象是更常见的场景。
我们就用redisTempate来编写测试代码
package com.example.redis;
import com.example.redis.domain.User;
import org.assertj.core.internal.bytebuddy.asm.Advice;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.Serializable;
import java.util.stream.IntStream;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisApplicationTests {
/*@Autowired
private RedisTemplate<String, Serializable> redisTemplate;*/
@Autowired
private RedisTemplate redisTemplate;
@Test
public void contextLoads() {
// 字符串测试
User user = new User();
user.setId(1L);
user.setName("小白一只");
user.setAge(18);
redisTemplate.opsForValue().set("user", user);
User newUser = (User) redisTemplate.opsForValue().get("user");
System.out.println("get user :" + newUser);
// 列表测试
/*ListOperations<String, Serializable> listOperation = redisTemplate.opsForList();
IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));*/
}
}
执行成功,然后使用medis可视化工具去查看redis数据库
注意是最后一个。发现居然乱码,而且类型为NONE,已经被清除掉了。
经过查阅得知,redisTemplate默认使用序列化器是JdkSerializationRedisSerializer,我们把它切换成GenericJackson2JsonRedisSerializer。
切换序列化器需要新建一个redisTemplate覆盖原本的redisTemplate并且保留除了序列化器的其他属性。以下是代码实现:
1 package com.example.redis.config; 2 3 import org.springframework.boot.autoconfigure.AutoConfigureAfter; 4 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 8 import org.springframework.data.redis.core.RedisTemplate; 9 import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 10 import org.springframework.data.redis.serializer.StringRedisSerializer; 11 12 import java.io.Serializable; 13 14 @Configuration 15 @AutoConfigureAfter(RedisAutoConfiguration.class) 16 public class RedisConfig { 17 18 /** 19 * 配置自定义redisTemplate 20 */ 21 /*@Bean 22 RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { 23 24 RedisTemplate<String, Object> template = new RedisTemplate<>(); 25 template.setConnectionFactory(redisConnectionFactory); 26 27 //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 28 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); 29 30 ObjectMapper mapper = new ObjectMapper(); 31 mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 32 mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 33 serializer.setObjectMapper(mapper); 34 35 template.setValueSerializer(serializer); 36 //使用StringRedisSerializer来序列化和反序列化redis的key值 37 template.setKeySerializer(new StringRedisSerializer()); 38 template.setHashKeySerializer(new StringRedisSerializer()); 39 template.setHashValueSerializer(serializer); 40 template.afterPropertiesSet(); 41 return template; 42 }*/ 43 44 /** 45 * 配置自定义redisTemplate 46 */ 47 @Bean 48 public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory redisConnectionFactory) { 49 RedisTemplate<String, Serializable> template = new RedisTemplate<>(); 50 template.setKeySerializer(new StringRedisSerializer()); 51 template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); 52 template.setConnectionFactory(redisConnectionFactory); 53 return template; 54 } 55 56 }
接下来修改测试代码
1 package com.example.redis; 2 3 import com.example.redis.domain.User; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.boot.test.context.SpringBootTest; 8 import org.springframework.data.redis.core.RedisTemplate; 9 import org.springframework.test.context.junit4.SpringRunner; 10 11 import java.io.Serializable; 12 13 @RunWith(SpringRunner.class) 14 @SpringBootTest 15 public class RedisApplicationTests { 16 17 @Autowired 18 private RedisTemplate<String, Serializable> redisTemplate; 19 20 @Test 21 public void contextLoads() { 22 // 字符串测试 23 User user = new User(); 24 user.setId(1L); 25 user.setName("小白一只"); 26 user.setAge(18); 27 redisTemplate.opsForValue().set("user", user); 28 User newUser = (User) redisTemplate.opsForValue().get("user"); 29 System.out.println("get user :" + newUser); 30 31 // 列表测试 32 /*ListOperations<String, Serializable> listOperation = redisTemplate.opsForList(); 33 IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));*/ 34 } 35 36 }
重新执行,执行结果如下:
查看redis数据库:
这些对了,可以看到保存就是一段json字符串。
redis常用有五种数据类型,分别是
- String (字符串)
- List (列表)
- Set (集合)
- Sort Set(有序集合)
- Hash(字典)
可以使用type命令查看类型,object encoding查看编码
关于redis对象的类型和编码以及底层数据结构的关系就需要去看看书籍了
在代码里面直接使用
分别对应不同类型进行操作,就行了。
我在测试代码里面写了个列表类型的使用代码
1 ListOperations<String, Serializable> listOperation = redisTemplate.opsForList(); 2 IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));
向redis数据库添加一个列表对象,key为list,值为item0~99,执行之后查看数据库:
没有问题,关于其他的集合、字典等操作,需要各位看官自行去实践。
值得注意的是,以上的操作中向redis添加数据都是我们自己写代码来做的。在实际应用场景中,比如将redis作为缓存的时候,可能代码中有
很多地方都会涉及到向redis添加、更新、删除数据,每个地方都自己写代码总是不太好的。因此Spring Cache整合了redis,基于注解的方式帮我们
简化了这些操作,关于使用redis做缓存的部分下篇文章会讲到。
本文到此结束,我是个小白,写的文章可能深度与广度都有所不足,同时也可能会有理解上的错误,望广大网友不吝指教。
参考文章:
一起来学SpringBoot | 第九篇:整合Lettuce Redis
springboot系列文章之 集成redis 服务 (Lettuce & Jedis)
书上说,天下没有不散的宴席。不要怕,书上还说了,人生何处不相逢。