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.GenericJackson2JsonRedisSerializerorg.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);
}

【结果】

在这里插入图片描述
多了个类全名,反序列化的对象的类型就可以从这里获取到。

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值