1. 程式人生 > >一次線上升級大規模報錯後,我又重新學習了序列化!

一次線上升級大規模報錯後,我又重新學習了序列化!

### 背景 去年9月份時候fastjson出現過一個漏洞,需要升級到1.2.60,舊版本是1.2.12,測試環境驗證完畢後上線,上線幾分鐘瞬間幾百封報錯郵件,當時瞬間心裡特緊張,但是表面上得裝著沒事,咱能搞定,哈哈,還好迅速定位並解決了問題。 ### 系統流程 出問題模組流程比較簡單,需要查詢一些資料,先從Redis查詢,沒有再查詢資料庫並把結果放到Redis中快取。 ### 問題排查 報錯異常資訊如下: ``` java.io.InvalidClassException: com.alibaba.fastjson.JSONObject; local class incompatible: stream classdesc serialVersionUID = -7894253080042154647, local class serialVersionUID = 1 ``` 看到報錯可能你已經明白了,反序列化時候版本不一致導致的問題,那麼問題是如何產生的呢? Fastjson1.2.60原始碼的JSONObject類裡有下面一行程式碼: ``` private static final long serialVersionUID = 1L; ``` 而1.2.12版本原始碼的JSONObject類裡沒有定義serialVersionUID。 Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的,在進行反序列化時,JVM會把傳來的位元組流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常 當實現java.io.Serializable介面的類沒有顯式地定義一個serialVersionUID變數時候,Java序列化機制會根據編譯的Class自動生成一個serialVersionUID作序列化版本比較用,這種情況下,如果Class檔案(類名,方法明等)沒有發生變化(增加空格,換行,增加註釋等等),就算再編譯多次,serialVersionUID也不會變化的。 問題原因找到了,系統返回實體裡存放了JSONObject的物件,系統上線後用戶訪問時候如果快取有資料,就會出現反序列化版本不一致的情況,導致出現異常。 ### 解決方案 先說下我的方案,使用新版本的jar包,把設定快取程式碼裡key的字首修改下,這樣就不會使用舊的快取進行反序列化,問題解決。 例如: ``` //原始程式碼 @CacheEvict(value="RedisCache11",key="'user:test:'+#obj.id",beforeInvocation=true) //修改後程式碼 @CacheEvict(value="RedisCache11",key="'user:test2020:'+#obj.id",beforeInvocation=true) ``` 以上是我的一種的解決方案,如果你有其他的方案,歡迎留言溝通哦! **推薦閱讀** [1.記一次線上Mysql慢查詢排查經歷!](https://mp.weixin.qq.com/s/fp708jy0_HBP7MChEf-4XA) [2.徹底理解cookie、session、token](https://mp.weixin.qq.com/s/AVwanj-benepE_AvYelHIg) [3.阿里面試官:分別說說微信和淘寶掃碼登入背後的實現原理?](https://mp.weixin.qq.com/s/cOdk9ofelda6npzvk8F1Vg) [4.一分鐘帶你瞭解下MyBatis的動態SQL!](https://mp.weixin.qq.com/s/FRvQeLgPY1Md1K2G3naK0Q) [5.原創 | 我是如何解決POI解析Excel出現的OOM問題的?](https://mp.weixin.qq.com/s/97UDUci8u8A3KNi7-xw9eQ) *** >如果覺得文章不錯,希望可以隨手轉發或者”在看“哦,非常感謝哈! >關注下方公眾號後回覆「1024」,有驚喜哦! ![](https://img2018.cnblogs.com/blog/463242/202001/463242-20200116154914338-370772914.