【全网首发】擦,就加了一个字段还能出事故?原创
“喂,老陈,走买咖啡去。”
“等下,我这有个需求现在得发个版。”
“擦,回来再发啊!”
“别急嘛 yes,很快的,就新加了个字段,稳的一批,两分钟!”
“行吧,就两分钟啊,我咖啡瘾上来了,赶紧的!”
…
老测试:“老陈,预发验证出错了,你看看。”
我:“擦,老陈你个废物,加个字段都能出错?”
老陈:“擦,老测试你干个der,qa环境怎么没测出来?”摸了摸光滑的头皮,老陈立马坐下开始排查了起来。
5分钟过去了。
老陈:“擦,yes,快帮我看下,我真的就加了个字段,啥都没干,咋反序列化就报错了,解决了我请你喝咖啡。”
哟,铁公鸡今天终于要拔毛了,我得好好宰他一顿:”行啊,我看看!你这项目存 redis 的 value 用的是不是 JDK 序列化?“
老陈看了我一眼:“是的,这老项目一直用的是 JDK 序列化”。
我又瞄了一眼他定义的类,实现了 Serializable 接口,没有显示定义 serialVersionUID,行吧,有数了。
“预发先回滚吧,这玩意暂时还不好解决。”我叉着手故作神秘道。
“草,你别装了,赶紧的!”
“别急别急,来,我先给你复现下报错!”
复现
我简单定义一个 Yes 类,可以看到就三个字段。
我简单 new 了一个对象,直接塞入到 redis 中。
可以看到 value 看起来是乱码,这里用的是 JDK 序列化。
现在我们在 Yes 类加个 hobby 这个字段,然后再从 redis 里面获取之前存入的值然后打印.
看看,是不是报错了,无法反序列化,老陈,你看看是不是预发报错一样?
老陈眼睛顿时亮了一下。
我战术性清了波嗓子,咳咳,我们再详细看下报错信息,里面有一行字,这就是抛错的具体原因,流里面 serialVersionUID 和本地的 serialVersionUID 不一样的。
为什么会这样?
我看了老陈一眼打算再给他一个战术性停顿。
老陈有点急眼了:“你丫的怎么这么欠揍,所以为什么会这样?”
我撩了一波头发,甩了他一眼,继续道:
可以看到,我们用的是 JDK 序列化,虽然 class 实现了 Serializable 接口但没显示定义 serialVersionUID ,这样一来序列化时会根据当前类的信息计算得到一个 serialVersionUID 。
在序列化存入 redis 后,我又把代码里的 class 的结构变了,这时候再从 redis 获取之前的值反序列化,由于当前的 class 还是没有 serialVersionUID 。
于是又会根据当前的类信息计算的 serialVersionUID ,而由于结构变了,类信息肯定变了,所以计算出来的 serialVersionUID 不一致。
因此序列化就失败。
这 serialVersionUID 就好比 class 的版本,版本变了序列化自然就失败了。
所以怎么解决呢?
我轻咳了一下,又瞄了老陈一眼,想从他那边来点反馈。
老陈当场就扬起手想抽我,我脖子一缩立马哔哔:解决方式就是显示制定 serialVersionUID,这样就不需要动态计算了。
你看,我先不加字段,在 class 上加下 serialVersionUID 重新塞一遍缓存。
然后再给 Yes 这个 class 加上 hobby 字段,紧接着从 redis 中取值反序列化输出
可以看到成功输出了, hobby 取不到值为 null。
咋样,老陈,懂了吧?
本畏缩坐着的老陈突然就站起来了,摸了摸他的光头,慢慢哟哟地走向他的座位,拉开抽屉,从中翻出了一袋…咖啡?随手扔给了我,“诺,你的咖啡,赶紧喝了,再两天要过期了”。
然后甩都不甩我,直接跟老测试哔:“那啥,得先把线上缓存的老数据删了,然后再发个版就行了,等低峰期再发吧。然后你这个测试不到位啊?这场景都想不到吗,啊?”
老测试有点委屈:“谁让 qa 环境没老数据,还不是因为每次你测试的时候,懒得告诉我 key ,直接让我 flush DB!”
老陈有点急了:“这还能怪我,我不管,反正是你没测到!”
老测试也急了:“这鬼场景管我测试 P 事!”
我看了看甩给我的咖啡,再看了眼拉扯的他们,嘀咕道:“有病,又没上生产吵个P,这老陈tmd真不是人,真的抠搜,擦!下次我肯定不帮他,让他哭去!”
我骂骂咧咧地带着咖啡和杯子走向了饮水机…嘚,剩波钱也挺好~
最后
好了,今天的故事就到此为止了。
总结下:
如果你了 JDK 序列化,一定记得要加 serialVersionUID ,不然就 G了。
还有,不是很推荐用 JDK 序列化,不管是性能还是存储都没有优势。
至于具体选择哪种序列化合适,后面我再写篇文章对比下市面上几个常见的序列化方式的优缺点,比如 Hessian、JSON、Protobuf 等。
好嘞,如果觉得故事不错,可以点赞转发一波。
我是yes,从一点点到亿点点,我们下篇见~