springboot使用Jedis
在springboot2.X版本后,默认使用的的redis客户端是Lettuce,如果项目中想要使用jedis,需要先把Lettuce依赖去掉,一般如下步骤
1.pom引入依赖
引入spring-boot-starter-data-redis
排除lettuce-core
引入jedis
2.编写RedisConfig
注入Jedis相关类,如JedisPoolConfig,RedisStandaloneConfiguration,JedisConnectionFactory,RedisTemplate
注意序列化问题
在创建RedisTemplate的时,如果项目使用比较简单,redis存储的是字符串,可以直接使用StringRedisTemplate,它用的是字符串的序列化器,如果redis想存储对象,则需要其他的序列化反序列化器,下面代码例子使用的是一个json的序列化器Jackson2JsonRedisSerializer
3.使用
导入依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
|
配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: application: name: redis-springboot redis: host: 192.168.72.30 port: 6379 password: 123321 jedis: pool: max-active: 8 min-idle: 0 max-wait: 100ms
|
java代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @SpringBootTest class RedisSpringbootApplicationTests { @Autowired private RedisTemplate redisTemplate;
@Test void testString() { ValueOperations ops = redisTemplate.opsForValue(); ops.set("name", "远哥"); String name = (String) ops.get("name"); System.out.println("name="+name); } }
|
问题
![](/../images/redis/r2.png)
怎么产生的
当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。
JdkSerializationRedisSerializer: 使用JDK提供的序列化功能。优点是反序列化时不需要提供类型信息(class),但缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化
缺点:
解决方法:
RedisTemplate中 value 的序列化,比较常用的是JdkSerializationRedisSerializer和GenericJackson2JsonRedisSerializer。
前者需要对象实现java.io.Serializable接口,并且序列化后结果较大,不易阅读,所以更推荐采用GenericJackson2JsonRedisSerializer方式。
测试:
User.java
1 2 3 4 5 6 7
| @Data @NoArgsConstructor @AllArgsConstructor public class User { private String name; private Integer age; }
|
RedisConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Configuration public class RedisConfig {
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String ,Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
return redisTemplate; }
}
|
1 2 3 4 5 6
| @Test void testSaveUser() { redisTemplate.opsForValue().set("user:100", new User("Vz", 21)); User user = (User) redisTemplate.opsForValue().get("user:100"); System.out.println("User = " + user); }
|
保存数据成功!
截图:
![](/../images/redis/r3.png)
尽管Json序列化可以满足我们的需求,但是依旧存在一些问题。
如上图所示,为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
那么我们如何解决这个问题呢?我们可以通过下文的StringRedisTemplate
来解决这个问题。
如上图保存的json数据: “@class”: “com.example.redisspringboot.domain.User”
StringRedisTemplate
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
![](/../images/redis/r4.png)
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程
- 我们可以直接编写一个测试类使用StringRedisTemplate来执行以下方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @SpringBootTest public class RedisStringTemplateTest { @Autowired private StringRedisTemplate stringRedisTemplate;
@Test void testSaveUser() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); String userJson1 = objectMapper.writeValueAsString(new User("Vz", 21)); stringRedisTemplate.opsForValue().set("user:100",userJson1); String userJson2 = stringRedisTemplate.opsForValue().get("user:100"); User user = objectMapper.readValue(userJson2, User.class); System.out.println("user = " + user); }
}
|
![](/../images/redis/r5.png)
此时已经没有了@class
总结
RedisTemplate的两种序列化实践方案,两种方案各有各的优缺点,可以根据实际情况选择使用。
方案一:
- 自定义RedisTemplate
- 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二:
- 使用StringRedisTemplate
- 写入Redis时,手动把对象序列化为JSON
- 读取Redis时,手动把读取到的JSON反序列化为对象