Redis 序列化 GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer的区别

Redis 序列化 GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer的区别,第1张

Redis 序列化 GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer的区别

文章目录
  • GenericJackson2JsonRedisSerializer
    • (1)VALUE 存普通对象
    • (2)VALUE 存对象集合
    • (3)VALUE 存JSON字符串
    • (4)管道Pipelined存数据
  • Jackson2JsonRedisSerializer
    • (1)VALUE 存普通对象
    • (2)VALUE 存JSON字符串
    • (3)管道Pipelined存数据

 
    @Bean
    public RedisTemplate functionDomainRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate redisTemplate = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key 都使用String 序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
 
GenericJackson2JsonRedisSerializer 

GenericJackson2JsonRedisSerializer序列化时,会保存序列化的对象的完全限定名,从redis获取数据时即可直接反序列化成指定的对象

通用参数如下:

List students = new ArrayList<>();
Student xm = new Student("小明", 12);
Student ph = new Student("胖虎", 12);
students.add(xm);
students.add(ph);
(1)VALUE 存普通对象

存:

  Student xm = new Student("小明", 12);
  redisTemplate.opsForValue().set(xm.getName(), xm);

值中附带了实体信息

取:

Student xmCache = (Student)redisTemplate.opsForValue().get(xm.getName());
// Student(name=小明, age=12)
System.out.println(xmCache);

结论:GenericJackson2JsonRedisSerializer 序列化方式 可直接存储VALUE为对象,且从Redis获取可进行强转

(2)VALUE 存对象集合

存:

redisTemplate.opsForSet().add("students-genericJackson2JsonRedisSerializer", students);
redisTemplate.opsForValue().set("students-str", students);

值中既有实体类完全限定名又有集合类型

具体值中携带了实体类完全限定名

取:

List studentCache = (List) redisTemplate.opsForValue().get("students-str");
Set members = redisTemplate.opsForSet().members("students-genericJackson2JsonRedisSerializer");
// [Student(name=小明, age=12), Student(name=胖虎, age=12)]
System.out.println(studentCache);
// [Student(name=胖虎, age=12), Student(name=小明, age=12)]
System.out.println(members);
 

结论:GenericJackson2JsonRedisSerializer 序列化方式 可直接存储VALUE为对象集合,且从Redis获取可进行强转

(3)VALUE 存JSON字符串
redisTemplate.opsForValue().set(ph.getName(), JSON.toJSONString(ph));

存:

无@class字段,且jSON字符串中含有转义符

取:

Object o = redisTemplate.opsForValue().get(ph.getName());
System.out.println(o);

注意点:因为这里存是JSON字符串,所以取数据时候,也无法直接强制转为Student对象,我们需要手动调用方法,将JSON字符串转换为JAVA对象

redisTemplate.opsForValue().set(ph.getName(), JSON.toJSONString(ph));
Object o = redisTemplate.opsForValue().get(ph.getName());
// Student(name=胖虎, age=12)
System.out.println(o == null ? null : JSON.parseObject(o.toString(), Student.class));

结论:GenericJackson2JsonRedisSerializer 序列化方式 可直接存储VALUE为JSON字符串形式,且从Redis获取后不可进行强转,需要将结果转为字符串,再将JSON字符串转为自己需要的对象或对象集合

(4)管道Pipelined存数据

存:

List students = new ArrayList<>();
Student xm = new Student("小明", 12); Student ph = new Student("胖虎", 12);
students.add(xm); students.add(ph);
redisTemplate.executePipelined((RedisCallback) conn -> {
    students.forEach(s -> conn.set(s.getName().getBytes(), JSON.toJSONString(s).getBytes()));
    return null;
});

管道 *** 作的数据并没有@class 实体类属性,实体类完全限定名丢失,那么这个时候还能否获取数据呢?

答案是不能

取:

取完直接强转:

Student xmCache = (Student)redisTemplate.opsForValue().get(xm.getName());
System.out.println(xmCache);

GET取完不强转

Object xmCache = redisTemplate.opsForValue().get(xm.getName());
System.out.println(xmCache);

MGET 批量获取

List objectList = redisTemplate.opsForValue().multiGet(students.stream().map(Student::getName).collect(Collectors.toList()));
System.out.println(objectList);
return objectList;
 

ERROR 16400 — [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Missing type id when trying to resolve subtype of [simple type, class java.lang.Object]: missing type id property ‘@class’
at [Source: (byte[])"{“age”:12,“name”:“小明”}"; line: 1, column: 26]; nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class java.lang.Object]: missing type id property ‘@class’
at [Source: (byte[])"{“age”:12,“name”:“小明”}"; line: 1, column: 26]] with root cause

翻译过来的意思是:无法读取 JSON:尝试解析 [简单类型,类 java.lang.Object] 的子类型时缺少类型 ID:缺少类型 id 属性“@class”

结论: 使用GenericJackson2JsonRedisSerializer 序列化进行管道 *** 作后,实体类@class属性会丢失,再次从redis获取数据将无法成功反序列化

Jackson2JsonRedisSerializer

通用参数如下:

List students = new ArrayList<>();
Student ys = new Student("亚索", 12);
Student mw = new Student("蛮王", 12);
students.add(ys);
students.add(mw);
(1)VALUE 存普通对象

存:

redisTemplate.opsForValue().set(ys.getName(), ys);
redisTemplate.opsForValue().set(mw.getName(), mw);

取:

Student ysCache = (Student)redisTemplate.opsForValue().get(ys.getName());
System.out.println(ysCache);

发现报错:java.lang.ClassCastException: java.util.linkedHashMap cannot be cast to com.leilei.entity.Student

断点调试:获取的ysCache 实际是一个linkedHashMap

Object ysCache = redisTemplate.opsForValue().get(ys.getName());
System.out.println(ysCache);

存对象集合结果一样…

redisTemplate.opsForValue().set("lol", students);
Object lolCache = redisTemplate.opsForValue().get("lol");
System.out.println(lolCache);

解决办法:

Jackson2JsonRedisSerializer序列化时 存数据都采用JSON字符串方式,然后取数据时也不直接将结果强转,而是使用JSON反序列化 将JSON字符串反序列化为java对象或集合

请看示例二:VALUE 存JSON字符串

结论:Jackson2JsonRedisSerializer序列化方式,如VALUE直接存对象或者对象集合,获取时结果为linkedHashMap,无法直接使用JDK强转方法转为对象或对象集合,需借助工具进行转换为实体与实体集合

(2)VALUE 存JSON字符串

存:

redisTemplate.opsForValue().set(ys.getName(), JSON.toJSONString(ys));
redisTemplate.opsForValue().set(mw.getName(), JSON.toJSONString(mw));

字符串中有转义字符

取:

Object ysCache = redisTemplate.opsForValue().get(ys.getName());
// Student(name=亚索, age=122)
System.out.println(ysCache == null ? null : JSON.parseObject(ysCache.toString(), Student.class));
List cacheList = redisTemplate.opsForValue().multiGet(students.stream().map(Student::getName).collect(Collectors.toList()));
List studentList = cacheList.stream().filter(Objects::nonNull).map(Object::toString).map(x -> JSON.parseObject(x, Student.class)).collect(Collectors.toList());
// [Student(name=亚索, age=122), Student(name=蛮王, age=234)]
System.out.println(studentList);
 

结论:Jackson2JsonRedisSerializer序列化方式,VALUE存JSON字符串时,取值也为JSON字符串,需借助JSON工具进行转换为实体类或实体集合

(3)管道Pipelined存数据

存:

redisTemplate.executePipelined((RedisCallback) conn -> {
    students.forEach(s -> conn.set(s.getName().getBytes(), JSON.toJSONString(s).getBytes()));
    return null;
});

取:

获取管道存储的值变为了linkedHashMap

因为我们需要将map转为java对象,我这里采用的是先转JSON字符串方式

List cacheList = redisTemplate.opsForValue().multiGet(students.stream().map(Student::getName).collect(Collectors.toList()));
if (CollectionUtils.isEmpty(cacheList)) {
    return null;
}
List studentList = cacheList.stream().filter(Objects::nonNull).map(JSON::toJSONString).map(x -> JSON.parseObject(x, Student.class)).collect(Collectors.toList());
// [Student(name=亚索, age=122), Student(name=蛮王, age=234)]
System.out.println(studentList);
 

结论:Jackson2JsonRedisSerializer 序列化方式,且使用管道 *** 作后,获取的值也是一个linkedHashMap,需借助工具才可将值反序列化为实体对象或实体对象集合

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5682600.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)