
點選上方藍字關注我們
點選下方在在看在走
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常
一、前言
今天調試分頁查詢代碼的時候遇到一個奇葩的問題,該問題後來排查下來跟
lombok
的使用有關。我們在使用
mybatis
或者
mybatis-plus
的時候一般會定義一個類對應表的每個字段,一個成熟的java程式員喜歡使用
lombok
把代碼簡潔點。這是大前提,我直接說結論吧:
實體類最好都加上
@Data
,
@AllArgsConstructor
,
@NoArgsConstructor
才能避免我現在遇到的問題
二、我的問題
我的表:
我的實體類:
然後一個普通的
select
查詢的時候報了下面這個錯誤:
可以看到異常很奇怪,我的
total_increase_percent
明明是
BigDecimal
,為何要被反序列化為
java.util.Date
呢?\
後面修改為如下代碼就正常了:
二、問題排查
-
首先定位到問題出現在哪裡
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
由于
是columnName
,該列不是total_increase_percent
,類型不一緻,是以報異常。是以要看卡timestamp
是如何擷取到的以及為何使用了rs
轉換該字段。org.apache.ibatis.type.DateTypeHandler
-
org.apache.ibatis.type.DateTypeHandler的擷取
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
點選調用棧的紅框出,跳轉到
和rs
的擷取處。org.apache.ibatis.type.DateTypeHandler
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
在
方法這裡既取到了createUsingConstructor
,又擷取到了typeHandler
rs
。
我們可以推斷出,應該是通過
和columnName
擷取parameterType
typeHandler
出錯了。
我們看看這裡的代碼:
看看
,parameterType
,columnName
三個值的類型:typeHandler
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
ok,這幾個值都吻合了,根據代碼
我們看出1-3行
和parameterType
沒對上導緻的。這裡可以推斷出columnName
出現了問題,為啥不懷疑是constructor
出現了問題了呢?因為columnName
是擷取到sql傳回結果構造的,是rsw
的代碼,大機率不會出現問題。mybatis
-
constructor分析
這是
的constructor
:parameterTypes
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
這裡出現了4個字段,但是沒有
,id
,gmtUpdate
這幾個字段,而看看gmtCreate
的rsw
的值:columnNames
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
這裡卻多了
,id
,gmtUpdate
這幾列,問題有進一步定位到了,原來是構造器的字段和gmtCreate
的rsw
不一一對應導緻的。可以從上面代碼columnNames
for
循環得知,都是根據索引一一擷取,這裡個數都對不上,肯定有問題了。
在這裡基本上已經定位到問題了,就是構造器隻接受了3個參數導緻的。
-
如何擷取到的constructor
把方法棧在往上移一個,就能找到
的具體擷取處:constructor
在這裡插入圖檔描述java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常
就是我的實體類,resultType
通過defaultConstructor
擷取到,這個方法就不細看了,裡面邏輯就是:如果隻有一個構造器,那就使用該構造器,擷取尋找被标記了findDefaultConstructor
注解的構造器。由于AutomapConstructor
注解隻能生成一個構造器@Data
,沒有OutputValueDO(java.math.BigDecimal,java.math.BigDecimal,java.math.BigDecimal,java.util.Date)
,id
,gmtUpdate
gmtCreate
。
此時就有一個解決方案了,去掉
,自己寫一個完整的構造器,包括繼承的所有字段,但是這樣是不太好的,從上面@Data
循環代碼可知,要資料庫的表的列的順序要和實體類的構造器的參數的順序一緻,不然還是出現問題。那就在往上個方法棧看看為什麼使用了該處理邏輯,印象中的for
沒這麼坑。mybatis
-
更優雅的解決方案
再往上到上一個方法棧,
方法就找到了正主。createResultObject
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 在這裡插入圖檔描述
由于
判斷為真就走到了通過構造器反射得到結果的邏輯。接下來分别分析這個!resultType.isInterface() && !metaType.hasDefaultConstructor()
if...else...
-
明顯我們沒有定義自己的hasTypeHandlerForResultObject
,故忽略typeHandler
-
表示在constructorMappings
中定義了實體類的字段和表字段的映射關系,但是我們沒有定義,忽略mapper.xml
- 我的實體類
不是接口,并且沒有無參構造器,我的代碼正好适合這個判斷,是以我要想辦法是這個判斷為假。OutputValueDO
-
最後一個就是預設的,我要改成走到這個方法來。
解決方案方向:加個預設構造器。加
即可解決,該注解就能生成無參構造器,由于我加了@NoArgsConstructor
,是以我還必須加@Builder
,穩了,解決了。@AllArgsConstructor
三、總結
我一般使用
lombok
最好加上這幾個注解:
但是這個代碼一開始不是我寫的,而且該實體類沒有繼承的話也不會出問題,巧了。以前也看過
mybatis
的代碼,但是沒有翻過映射這塊。今天再一次體味到了
mybatis
的代碼:真正牛的代碼不需要注釋。很容易就找到了問題。
- 我的微信: 在這裡插入圖檔描述
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常 - 我的微信公衆号: 雲原生玩碼部落
java mybatis sql 查詢耗時_Mybatis反序列化sql查詢結果異常