redisTemplate序列化

912 阅读2分钟

redisTemplate序列化

JdkSerializationRedisSerializer

在没有序列化之前,调用put方法

@Resource
private RedisTemplate<String,String> redisTemplate;
​
redisTemplate.opsForHash().put(key,"name","张三");

缓存中结果是乱码

image-20211226094154636.png

这是因为redisTemplate默认为JdkSerializationRedisSerializer序列化

image-20211226102521014.png

查看对应redis内容

String key = "demo.user.info";
User user = User.builder().id(1).name("张三").count(22.11).birth(
        Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())).build();
redisTemplate.opsForHash().put(key,"name","张三");
System.out.println(redisTemplate.boundHashOps(key).keys());
System.out.println(redisTemplate.boundHashOps(key).values());
System.out.println(redisTemplate.boundHashOps(key).entries());
​
//输出
[name]
[张三]
{name=张三}

虽然这种默认序列化方式显示乱码,但也不会影响我们读取到得数据,只是在缓存中无法直观看到数据内容,很是不便

StringRedisSerializer

通过StringRedisTemplate进行上面相同操作

@Resource
private StringRedisTemplate stringRedisTemplate;
​
String key = "demo.user.info";
stringRedisTemplate.opsForHash().put(key,"name1","李四");
System.out.println(stringRedisTemplate.boundHashOps(key).entries());
​
//输出
{name1=李四}

查看缓存中数据

image-20211226100444786.png

这次缓存中没有乱码,查看源码,看到该类继承并改变了RedisTemplate默认Jdk序列化的方式,由StringRedisSerializer来实现,并和名字呼应

image-20211226101139388.png

各种序列化对比

目前springboot 2.xx版本主要有这几种不同的序列器

名称说明特点
GenericJackson2JsonRedisSerializer基本和上面的Jackson2JsonRedisSerializer功能差不多,使用方式也差不多不需要指定序列化对象的类型信息
GenericToStringSerializer他需要调用者给传一个对象到字符串互转的Converter(相当于转换为字符串的操作交给转换器去做)比较不推荐使用,不如StringRedisSerializer方便
Jackson2JsonRedisSerializer对象以Json的形式存储,效率高且对调用者友好1:速度快,效率高 2:必须提供要序列化对象的类型信息(.class对象)
JacksonJsonRedisSerializer已过期
JdkSerializationRedisSerializerRestTemplate类默认的序列化方式1:必须实现java.io.Serializable接口,序列化后的数据庞大,比较笨重 2:存储的格式是二进制,不方便直观看数据
OxmSerializer以xml格式存储。析起来也比较复杂,效率也比较低
StringRedisSerializerStringRedisTemplate默认的序列化方式,key和value都会采用此方式进行序列化,是被推荐使用的,对开发者友好,轻量级,效率也比较高

Jackson2JsonRedisSerializer

RedisTemplate<String,Object> jackson2JsonRedisTemplate = new RedisTemplate<>();
jackson2JsonRedisTemplate.setConnectionFactory(this.redisConnectionFactory);
jackson2JsonRedisTemplate.setKeySerializer(new StringRedisSerializer());
//指定value的序列化为Jackson2JsonRedisSerializer
jackson2JsonRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(User.class));
//设置后必须调用该方法生效 否则会抛出 IllegalArgumentException: template not initialized; call afterPropertiesSet() before using it
jackson2JsonRedisTemplate.afterPropertiesSet();
String key = "demo.user.info";
User user = User.builder().id(1).name("张三").count(22.11).birth(
        Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())).build();
jackson2JsonRedisTemplate.opsForValue().set(key,user);
System.out.println(jackson2JsonRedisTemplate.opsForValue().get(key));
​
//输出
User(id=1, name=张三, count=22.11, birth=Sun Dec 26 16:06:35 CST 2021)

查看redis中数据

image-20211226201132734.png

new Jackson2JsonRedisSerializer(User.class)初始化是制定了序列化的类型,这种需要指定类型的方式不适合做全局的序列化配置

image-20211226201524042.png

GenericJackson2JsonRedisSerializer

代码配置如下

RedisTemplate<String,Object> genericRedisTemplate = new RedisTemplate<>();
genericRedisTemplate.setConnectionFactory(this.redisConnectionFactory);
genericRedisTemplate.setKeySerializer(new StringRedisSerializer());
genericRedisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//设置后必须调用该方法生效 否则会抛出 IllegalArgumentException: template not initialized; call afterPropertiesSet() before using it
genericRedisTemplate.afterPropertiesSet();
String key = "demo.user.info";
User user = User.builder().id(1).name("张三").count(22.11).birth(
        Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())).build();
genericRedisTemplate.opsForValue().set(key,user);
System.out.println(genericRedisTemplate.opsForValue().get(key));
​
//输出
User(id=1, name=张三, count=22.11, birth=Sun Dec 26 20:22:10 CST 2021)

查看缓存中的数据

image-20211226202401789.png

这种序列化方式不用自己手动指定对象的Class,缓存中会有存储数据的类型,比较适合做一个全局的通用序列化配置