RedisTemplate及4种序列化方式
RedisTemplate及4种序列化方式
目录
引言
使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板类 RedisTemplate, 今天我们好好的看看这个模板类 。
一、RedisTemplate
看看4个序列化相关的属性 ,主要是用于 KEY 和 VALUE 的序列化 。 举个例子,比如说我们经常会将POJO 对象存储到 Redis 中,一般情况下会使用 JSON 方式序列化成字符串,存储到 Redis 中 。
Spring提供的Redis数据结构的操作类
- ValueOperations 类,提供 Redis String API 操作
- ListOperations 类,提供 Redis List API 操作
- SetOperations 类,提供 Redis Set API 操作
- ZSetOperations 类,提供 Redis ZSet(Sorted Set) API 操作
- GeoOperations 类,提供 Redis Geo API 操作
- HyperLogLogOperations 类,提供 Redis HyperLogLog API 操作
二、StringRedisTemplate
再看个常用的 StringRedisTemplate
RedisTemplate<K, V> 支持泛型,StringRedisTemplate K V 均为String类型
StringRedisTemplate 继承 RedisTemplate 类,使用 StringRedisSerializer 字符串序列化方式
三、RedisSerializer 序列化接口
RedisSerializer 接口是 Redis 序列化接口,用于 Redis Key、Value、HashKey、HashValue 的序列化
RedisSerializer 接口的实现类如下
归类一下
- JDK 序列化方式(RedisTemplate 默认)
- String 序列化方式(StringRedisTemplate 默认)
- JSON 序列化方式
- XML 序列化方式
3.1 JDK 序列化方式 (默认)
org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
,默认情况下,RedisTemplate 使用该数据列化方式
我们来看下源码 RedisTemplate afterPropertiesSet()
Spring Boot 自动化配置 RedisTemplate Bean 对象时,就未设置默认的序列化方式。
绝大多数情况下,不推荐使用 JdkSerializationRedisSerializer 进行序列化。主要是不方便人工排查数据,且操作的对象还需要实现 Serializable 接口。
我们来做个测试
运行单元测试
KEY 前面带着奇怪的 16 进制字符 , VALUE 也是一串奇怪的 16 进制字符 。。。。。
为什么是这样一串奇怪的 16 进制? 字节流 ObjectOutputStream writeString(String str, boolean unshared) 实际就是标志位 + 字符串长度 + 字符串内容
KEY 被序列化成这样,线上通过 KEY 去查询对应的 VALUE非常不方便,所以 KEY 肯定是不能被这样序列化的。
VALUE 被序列化成这样,除了阅读可能困难一点,不支持跨语言外,实际上也没还OK。不过,实际线上场景,还是使用 JSON 序列化居多。
3.2 String 序列化方式
org.springframework.data.redis.serializer.StringRedisSerializer
,字符串和二进制数组的直接转换。默认情况下,StringRedisTemplate 使用该数据列化方式
绝大多数情况下,我们 KEY 和 VALUE 都会使用这种序列化方案。
3.3 JSON 序列化方式
在将对象数据缓存到 Redis 中,我们一般采用 String + Json 的序列化方式。
org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
和 org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
都是Jackson 实现 JSON 的序列化方式,前者默认会在序列化的时候将类全名写到Json中,从而实现反序列化,而后者则需要自己配置。
推荐使用 Jackson2JsonRedisSerializer,相比 GenericJackson2JsonRedisSerializer 占用内存小,效率高。
【配置类】
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 配置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
// 使用StringRedisSerializer来序列化和反序列化Redis的key值
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用Jackson2JsonRedisSerializer来序列化和反序列化Redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
// 配置对象映射器
JacksonObjectMapper objectMapper = new JacksonObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围。ANY指包括private和public修饰符范围
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入类型,类的信息也将添加到json中,这样才可以根据类名反序列化。
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
// 将对象映射器添加到序列化器中
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 配置key,value,hashKey,hashValue的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
// 反序列化-日期时间指定格式
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
// 序列化-日期时间指定格式
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
【单元测试】
@Test
void test() {
ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
// 存对象
User user = new User();
user.setName("小明");
user.setAge(18);
user.setAddress("Beijing");
user.setBirthday(LocalDateTime.now());
opsForValue.set("user", user);
// 取对象
user = (User) opsForValue.get("user");
System.out.println(user);
}
【结果】
多了个类全名,反序列化的对象的类型就可以从这里获取到。
更多推荐
所有评论(0)