MyBatis 替換成 MyBatis-Plus
背景介紹
一個老項目,數據庫用的是?MySQL?5.7.36?,?ORM?框架用的?MyBatis?3.5.0?,?mysql-connector-java?版本是?5.1.26?
新來了一個干練的小伙,精力充沛,看著就是一個喜歡折騰的主
他就覺得?MyBatis?使用起來不夠簡單,要寫的代碼還比較多,覺得有必要替換成?MyBatis-Plus?
Mybatis-Plus 替換 Mybatis
先準備一張表?tbl_order?,然后初始化 2 條數據
?View Code
為了簡化演示,我就直接用?Mybatis-Plus?搭建一個示例?demo?,以此來模擬下?"小伙"?替換的過程
只是用?MyBatis-Plus?替換?MyBatis?,其他組件的版本暫不動
Mybatis-Plus?版本就用?"小伙"?引用的版本:?3.1.1?,?mysql-connector-java?版本保持不變還是?5.1.26?
示例代碼:play_it_safe
此時運行?com.qsl.OrderTest#orderListAllTest?,會報錯,異常信息如下
?View Code
注意看?Caused by?
不支持的轉換類型:?java.time.LocalDateTime?
誰不支持??mysql-connector-java?不支持!
那?mysql-connector-java?哪個版本支持了,答案是:?5.1.37?
升級mysql-connector-java
將?mysql-connector-java?升級到?5.1.37?,再執行下?com.qsl.OrderTest#orderListAllTest?
不再報異常,查詢結果也正確
MyBatis-Plus?替換?Mybatis?似乎就完成了
順的讓人有點懷疑
Conversion not supported for type java.time.LocalDateTime
我們再回過頭去看看前面說到的異常:?Conversion not supported?for?type java.time.LocalDateTime?
Mybatis-Plus?替換?MyBatis?之前沒這個異常,替換之后就有了這個異常,這不是?Mybatis-Plus?的問題?
如何找這個異常的根因了?
很簡單,直接從異常堆棧入手
點了之后,你會發現方法很簡單
這么簡單的代碼能有什么問題?
大家注意看圖中左上角?MyBatis?的版本,是?3.5.1,并不是最初的 3.5.0
有小伙伴可能會問了:不是用?MyBatis-Plus?替換了?MyBatis?嗎,怎么還有?Mybatis??
這個問題問的真的好,我只想給你個大嘴巴子
你看下?MyBatis-Plus?的官方說明
既然基于?Mybatis?3.5.0?沒有拋異常,而基于?3.5.1?拋了異常,?LocalDateTimeTypeHandler?在?3.5.1?肯定做了調整
我們來看下調整了什么?
看出什么了?
MyBatis 3.5.0?會處理?LocalDateTime?類型的轉換(將?java.sql.Timestamp?轉換成?java.time.LocalDateTime?)
然而,注意了,然而來了!!!
然而從??MyBatis 3.5.1?開始,不再處理?LocalDateTime?(還包括:?LocalDate?、?LocalTime?)類型的轉換
而是交由?JDBC?組件,也就是?mysql-connector-java?來實現
而巧的是,?mysql-connector-java 5.1.26?不支持類型?LocalDateTime?
那它支持哪些類型了?
我們同樣從異常堆棧入手
點了之后,可以看到下圖
往上滑動鼠標,就可以看到支持的類型了
確實沒有?LocalDateTime?、?LocalDate?和?LocalTime?
mysql-connector-java 5.1.37?開始支持?LocalDateTime?、?LocalDate?和?LocalTime?,前面已經介紹過了,不再過多贅述
總結下異常根因:?MyBatis 3.5.1?開始不再處理?LocalDateTime?、?LocalDate?和?LocalTime?的轉換,而?mysql-connector-java 5.1.37?之前都不支持這些類型
弄清楚這個異常的來龍去脈之后,順的是不是又理所當然一些了?
暴風雨的來臨
版本上線沒 2 天,該來的終究還是來了
我們往表?tbl_order?中插入一條記錄:?INSERT INTO `tbl_order` VALUES (3, 'asdfgh', NULL, '2024-02-21 20:01:31.111', '2024-02-21 20:02:56.764');?
再執行?com.qsl.OrderTest#orderListAllTest?
此刻我就想問?"小伙"?:刺不刺激?
碰到了異常,那就找原因
同樣從異常堆棧入手
看出什么了?
如果?getTimestamp(columnIndex)?得到的是?NULL?,不就?NullPointerException?? 嚴謹性了?
修復問題要緊,我們先看哪個版本進行修復了?
將?mysql-connector-java?升級到?5.1.42?
問題得以修復
經此一役,?"小伙"?似乎成長了很多,但眼里的光卻暗淡了不少
mybatis-plus-issues-1114
無意中看到了這個issue-1114,跟我們前面分析的?Conversion not supported?for?type java.time.LocalDateTime?是不是同一個問題?
只是我們用到的數據庫連接池是默認的?HikariCP?而非?Druid?
結合druid/issues/3302來看,如果使用?Druid?作為數據庫連接池,出現的異常可能跟我們前面分析的確實不一樣
所以大家需要根據自己的實際情況來分析,但針對異常的分析方法是通用的
修了“不該修的Bug”
這是我親身經歷的一次事故,到現在都覺得這鍋背的有點冤
背景介紹
文件分為主文件和附屬文件,主文件生成之后再生成附屬文件
附屬文件生成的時候,會校驗其依賴的主文件是否都生成了,如果有任意一個主文件未生成,依賴文件不能生成并拋出異常
這個業務還是比較簡單吧
但在附屬文件校驗的優化上,我背上了生產事故
優化前的校驗
listFileGenerateLog?作用是根據參數查詢文件生成記錄,具體實現不用關注
這個校驗邏輯是什么?只要有任意一個主文件生成,校驗就算通過了,與業務要求(主文件全部生成,才算校驗通過)不匹配呀
這不是妥妥的?Bug??
優化后的校驗
碰到?Bug?你能忍?我是忍不了一點,反手就是一個優化
這是不是就符合業務要求了?
生產異常
中午升級之后,穩定運行了一段時間,期間文件正常生成,沒出現任何問題
晚上 19 點,有個附屬文件生成失敗,異常提示:?依賴的資源[abc_{yyyyMMdd}.txt]未生成?
當時看到這個異常的第一眼,覺得既熟悉又陌生,熟悉的是這個異常信息的結構,陌生的是?abc_{yyyyMMdd}.txt?,這不是文件名嗎?
正常來講應該是?fileId?,是一個自增的正整數呀,怎么會是文件名了?
腦中瞬間閃過一個念頭:數據庫數據有問題?
一查嚇一跳,這個附屬文件關聯主文件的字段值是:?4356,abc_{yyyyMMdd}.txt?,看最終修改時間是:?2021-08-21 15:22:12.652?
4356?文件的文件名就是?abc_{yyyyMMdd}.txt?,正常來講,這個關聯字段的值應該是:?4356?
敢情這個?校驗Bug?完美的兼容了這個臟數據?,所以幾年了,一直沒出現異常
是不是有這味了?
這可倒好,我把?Bug?修好,還出現問題了,你說我是不是手賤?
經此一役,我眼里的光又暗淡了些許
總結
關于對組件的升級,或者對舊代碼的調整,都有可能牽一發動全身,影響甚大。
我的觀點是:能不動就不要動,改好沒績效,改出問題要背鍋,吃力不討好,又不是不能跑。
如果到了不得不改的地步了,那就需要全面的測試。