【RedisUtils工具类专题】Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer的对比分析


文章目录

  • 前言
  • 一、常用的RedisSerializer介绍
  • 二、Jackson2JsonRedisSerializer的特点
    • 1.将RedisSerializer改为Jackson2JsonRedisSerializer
    • 2.序列化和反序列化Object类(以User为例,不实现Serializable接口)
    • 3.序列化和反序列化String类
    • 4.序列化和反序列化Object类数组
    • 5.序列化和反序列化String数组
  • 三、GenericFastJsonRedisSerializer的特点
    • 1.将RedisSerializer改为GenericFastJsonRedisSerializer
    • 2.序列化和反序列化Object类(以User为例,不实现Serializable接口)
    • 3.序列化和反序列化String类
    • 4.序列化和反序列化Object类数组
    • 5.序列化和反序列化String数组
  • 总结


前言

在SpringBoot中使用Redis数据库时,如果RedisSerializer使用JdkSerializationRedisSerializer(默认值),需要被序列化Class实现Serializable接口,而且Redis数据库中数据很不直观(下图为Redis中存储的User类),不利于程序的调试和使用。

代码如下(以User为例,需实现Serializable接口):

User user = new User();
user.setId("1");
user.setUsername("zs");
user.setPassword("123");
RedisUtils.set("key",user);
User valueRedis = (User)RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:\xac\xed\x00\x05t\x00\x03key
Redis中的value:\xac\xed\x00\x05sr\x00\x1ecom.carl.security.entity.User1\xa1\xfd\xa2\xa8\xddV\xce\xc0\x02\x00\x03L\x00\x02idt\x00\x12Ljava/lang/String;L\x00\x08passwordq\x00~\x00\x01L\x00\x08usernameq\x00~\x00\x01xpt\x00\x011t\x00\x03123t\x00\x02zs


一、常用的RedisSerializer介绍

目前常用的RedisSerializer包括:JdkSerializationRedisSerializer(默认值)、StringRedisSerializer、Jackson2JsonRedisSerializer/GenericJackson2JsonRedisSerializer、GenericFastJsonRedisSerializer(来自com.alibaba.fastjson.support.spring包)等,正如前言所说,JdkSerializationRedisSerializer面临各种问题,所以这里主要介绍Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer两种RedisSerializer的特点与不足。
提示:本文中对于key都采用StringRedisSerializer进行序列化。

二、Jackson2JsonRedisSerializer的特点

1.将RedisSerializer改为Jackson2JsonRedisSerializer

代码如下:

@Component
public class RedisUtils {
    private static RedisTemplate<String, Object> redisTemplate;
    public static RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }
    @Autowired
    private RedisUtils(RedisConnectionFactory redisConnectionFactory){
        //为了方便,一般直接使用
        redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 将对象序列化
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        // json序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String 的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value的序列化方式采用jackson的方式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
    }
    public static boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public static Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
}

2.序列化和反序列化Object类(以User为例,不实现Serializable接口)

Redis中存储结果如下:

Redis中的key:key
Redis中的value:{"@class": “com.carl.security.entity.User”, “id”: “1”, “username”: “zs”, “password”: “123”}
其序列化和反序列化都可正常进行。

3.序列化和反序列化String类

代码如下:

RedisUtils.set("key","value");
String valueRedis = (String) RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:value
其序列化和反序列化都可正常进行。

4.序列化和反序列化Object类数组

代码如下:

User[] value = new User[]{user,user};
RedisUtils.set("key","value");
User[] valueRedis = (User[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:
[
“[Lcom.carl.security.entity.User1;”,
[
{
“@class”: “com.carl.security.entity.User1”,
“id”: “1”,
“username”: “zs”,
“password”: “123”
},
{
“@class”: “com.carl.security.entity.User1”,
“id”: “1”,
“username”: “zs”,
“password”: “123”
}
]
]

其序列化和反序列化都可正常进行。

5.序列化和反序列化String数组

代码如下:

String[] value = new String[]{"a","b","c","d"};
RedisUtils.set("key", value);
String[] valueRedis = (String[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:[“a”, “b”, “c”, “d”]
其序列化可正常进行,但是反序列化有问题,异常信息如下:

Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'a' as a subtype of `java.lang.Object`: no such class found
 at [Source: (byte[])"["a","b","c","d"]"; line: 1, column: 6]

综合上一节结论,可以发现:Jackson2JsonRedisSerializer对String数组进行序列化时会省略其类型的描述,直接进行存储,因此导致反序列化时认为“a”是一个类型参数,导致反序列化失败,该问题作者暂未发现解决方法

三、GenericFastJsonRedisSerializer的特点

1.将RedisSerializer改为GenericFastJsonRedisSerializer

代码如下:

@Component
public class RedisUtils {
    private static RedisTemplate<String, Object> redisTemplate;
    public static RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }
    @Autowired
    private RedisUtils(RedisConnectionFactory redisConnectionFactory){
        //为了方便,一般直接使用
        redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // json序列化配置
        GenericFastJsonRedisSerializer jackson2JsonRedisSerializer = new GenericFastJsonRedisSerializer();
        //key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String 的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value的序列化方式采用jackson的方式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
    }
    public static boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public static Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
}

2.序列化和反序列化Object类(以User为例,不实现Serializable接口)

Redis中存储结果如下:

Redis中的key:key
Redis中的value:{"@type": “com.carl.security.entity.User”, “id”: “1”, “username”: “zs”, “password”: “123”}
其序列化和反序列化都可正常进行。

3.序列化和反序列化String类

代码如下:

RedisUtils.set("key","value");
String valueRedis = (String) RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:value
其序列化和反序列化都可正常进行。

4.序列化和反序列化Object类数组

代码如下:

User[] value = new User[]{user,user};
RedisUtils.set("key","value");
User[] valueRedis = (User[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:
[
{
“@type”: “com.carl.security.entity.User”,
“id”: “1”,
“password”: “123”,
“username”: “zs”
},
{
“$ref”: “$[0]”
}
]

其序列化可正常进行,但是反序列化报异常,异常信息如下:

java.lang.ClassCastException: com.alibaba.fastjson.JSONArray cannot be cast to [Lcom.carl.security.entity.User;

从异常信息我们可以看出,GenericFastJsonRedisSerializer是将数组反序列化为JSONArray ,查看JSONArray类的定义就可以看出其是一种List集合,所以将其强转为User数组就会报错。

public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {
......
}

修改反序列化后的强转类型,就没有异常信息了。

List<User> valueRedis = (List<User>)RedisUtils.get("key");

5.序列化和反序列化String数组

代码如下:

String[] value = new String[]{"a","b","c","d"};
RedisUtils.set("key", value);
List<String> valueRedis = (List<String>)RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:[“a”, “b”, “c”, “d”]
其序列化和反序列化都可正常进行。


总结

本文对几种常见的RedisSerializer进行对比分析,总结出Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer的技术特点和目前遇到的问题,结论如下:

  1. Jackson2JsonRedisSerializer对String数组进行序列化时会省略其类型的描述,直接进行存储,因此导致反序列化时认为“a”是一个类型参数,导致反序列化失败(该问题作者暂未发现解决方法);
  2. GenericFastJsonRedisSerializer是将数组反序列化为JSONArray ,查看JSONArray类的定义就可以看出其是一种List集合,所以需要注意其强转的数据类型;
  3. 鉴于遇到的问题以及配置的复杂难度,建议选用GenericFastJsonRedisSerializer作为RedisSerializer。

你可能感兴趣的:(redis工具,java,redis)