Redis 序列化和反序列化
Posted
技术标签:
【中文标题】Redis 序列化和反序列化【英文标题】:Redis Serialization and Deserialization 【发布时间】:2015-08-28 00:04:04 【问题描述】:我注意到我存储在 Redis 中的一些序列化对象存在反序列化问题。
这通常发生在我对存储在 Redis 中的对象类进行更改时。
我想了解问题,以便为解决方案制定清晰的设计。
我的问题是,是什么导致了反序列化问题? 移除公共/私有财产会导致问题吗? 添加新属性,也许? 向类中添加新功能会产生问题吗?更多的构造函数怎么样?
在我的序列化对象中,我有一个属性 Map,如果我更改(更新一些属性、添加功能等)myObject,会导致反序列化问题吗?
【问题讨论】:
【参考方案1】:导致反序列化问题的原因是什么?
在回答你的问题之前,我想给你一些背景知识,
序列化运行时将一个版本号与每个可序列化类相关联,称为 serialVersionUID,在反序列化期间使用该版本号来验证序列化对象的发送方和接收方是否已为该对象加载了与序列化兼容的类。如果接收方为对象加载了一个类,该对象的 serialVersionUID 与相应发送方的类不同,则反序列化将导致 InvalidClassException。
如果一个可序列化的类没有显式声明一个serialVersionUID,那么序列化运行时将根据该类的各个方面为该类计算一个默认的serialVersionUID值,它使用该类的以下信息来计算SerialVersionUID,
-
类名。
写成 32 位整数的类修饰符。
按名称排序的每个接口的名称。
对于按字段名称排序的类的每个字段(私有静态和私有瞬态字段除外:
字段的名称。
以 32 位整数形式写入的字段修饰符。
字段的描述符。
如果存在类初始化器,请写出以下内容:
方法的名称,.
方法的修饰符,java.lang.reflect.Modifier.STATIC,写成32位整数。
方法的描述符,()V。
对于按方法名称和签名排序的每个非私有构造函数:
方法的名称,.
方法的修饰符写成 32 位整数。
方法的描述符。
对于按方法名称和签名排序的每个非私有方法:
方法的名称。
方法的修饰符写成 32 位整数。
方法的描述符。
所以,回答你的问题,
移除公共/私有财产会导致问题吗?添加新属性,也许?向类中添加新功能会产生问题吗?更多的构造函数怎么样?
是的,所有这些默认添加/删除都会导致问题。
但解决此问题的一种方法是显式定义 SerialVersionUID,这将告诉序列化系统我知道该类会随着时间的推移而演变(或演变)并且不会引发错误。所以反序列化系统只读取两边都存在的那些字段并赋值。反序列化端新添加的字段将获得默认值。如果在反序列化端删除了某些字段,算法只是读取并跳过。
以下是声明 SerialVersionUID 的方式,
private static final long serialVersionUID = 3487495895819393L;
【讨论】:
非常感谢您提供的信息丰富的回答。我还有另一个问题需要澄清。当您说“显式定义 SerialVersionUID”时,可以将此 UID 定义为默认值“private static final long serialVersionUID = 1L;”吗? 我的意思是,如果 CLASS 没有声明 UID,那么它将使用 DEFAULT。但!如果我声明了一个 UID,但它的值仍然是 DEFAULT 怎么办?它还会计算 UID 吗? 您好,您可以定义任何值,只要两边的值相同即可。顺便说一下 1L 不是默认值,你可以认为它是一个版本号。 那么 serialVersionUID 本身是否应该是瞬态的?我猜不是,但是它可能会在 redis 中一遍又一遍地使用大量内存来存储相同的值?以上是关于Redis 序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章
go-redis 基于beego正确使用序列化存储数据和反序列化获取数据