1.in導致的異常
Data truncation: Truncated incorrect DOUBLE value:
異常過程:
mapper接口如下:
public int updateBatchId(@Param("batchId")String batchId,@Param("idStr")String idStr);
xml中sql如下:
<update id="updateBatchId" parameterType="java.lang.String"> update pdm_description_error_msg set batch_id = #{batchId},status = "1",process_num = process_num +1 where id in (#{idStr}) </update>
原因分析:
mybatis中in不能這樣寫,需要使用foreach,不然就會報如上的錯誤。
解決辦法:(這里的idStr是以逗號分隔的,形式是這樣的:1,2,3,4)
<update id="updateBatchId" parameterType="java.lang.String"> update pdm_description_error_msg set batch_id = #{batchId},status = "1",process_num = process_num +1 where id in <foreach item="item" index="index" collection="idStr.split(',')" open="(" separator="," close=")"> '${item}' </foreach> </update>
異常總結
之前寫sql時是使用注解的方式寫的,通過那種方式,在java代碼中是可以直接使用以逗號分隔的字符串的,例子如下:
public String updateBatchId(String batchId,String idStr){ StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("update pdm_error_msg set batch_id = '" + batchId + "',status=1,process_num=process_num+1 where " + " (status=0 or status = 3) and id in ("+idStr+")"); return stringBuilder.toString(); }
這個是在java中直接拼接的sql可以,可以直接使用帶逗號的字符串,在xml不行。
2.group_concat
這個mysql中關鍵字其實一般是不會使用的,但是有時使用group by做分組的時候,又希望把分組的結果拿出來,就可能會使用這個關鍵字,但是,重點是這個但是,如果返回的字段的長度過長,就會直接截斷,然后也不拋異常,然后返回出來的結果就是一個階段后的結果。
為啥要截斷呢?
mysql為了優化性能
那多長會截斷呢?
默認就是1024個字節,這才多長啊。
能不能避免不被截斷?
可以,不過需要mysql的權限,讓dba設置,不過dba爸爸估計不會幫這個忙
總結
嚴格來說這個鍋不是mybatis的鍋,其實是mysql為了優化性能搞的,舉個例子,如果你程序開發測試環境隨便造的數據,都很短,沒問題,當部署到生產環境,運行一段時間,出問題,那估計問題就很嚴重。
3.is not null 和 != ; is null 和 =
這個在平時寫sql的時候一般沒什么問題,遇見null值判斷,都會使用is,或者is not,但是偶爾會寫成!=,這就搞飛機了,寫成這樣sql也不會拋異常,但是就是統計的數據不准確。原因就是null值不能使用 =,!=,<>等判斷。
4.provider中sql語句把反斜線去掉,導致的轉義問題
更新於--------------------------------------2020-01-15---------------------------------------
springboot中使用mybatis,現在很多小伙伴都不使用xml的方式寫sql了,而是通過provider,如果牽涉到批量操作,基本上大家都不會直接在mapper中寫sql,而是在provider中通過字符串拼接的方式來實現sql,這個寫一般的sql沒什么問題,一旦遇見一些坑爹的場景其實還是xml的方式比較好,比如下面說的問題:
場景:把表A中的message字段批量讀出來,一次讀取100條,批量插入到表B,實現方式是在provider中實現字符串拼接
代碼如下:
public String insertCheckMsgBatch(List<CheckMsg> msgList) { StringBuffer sql = new StringBuffer(); sql.append("insert into table(message,status) values "); if(!CollectionUtils.isEmpty(msgList)) { int i = 0; for(CheckMsg msg : msgList) { i++; sql.append("("+msg.getMessage()+","+msg.getStatus()); if(i < msgList.size()) { sql.append("),"); } else { sql.append(")"); } } } return sql.toString(); }
出現的問題: 由於表A中的message帶有轉義字符,會把字符串中的單引號和雙引號轉義,但是被上面一搞,所有的轉義字符都沒了,比如 "\"abc\'" 經過這玩意一搞變成了 ""abc'",但是這個也可以正常插入數據庫,但是下次讀出來就會出問題,因為這是一個異常的字符串。
解決辦法:
上面問題的根源在於通過provider沒有經過PreparedStatement預編譯,如果經過這個預編譯mybatis其實是可以處理這些特殊的字符的,ok,那就想辦法讓mybatis預編譯,有兩種方法,一種是改成xml方式,這種還要改,麻煩,另一個種是直接通過在mapper文件中寫批處理sql的方式,這種實際和在xml一樣。如下:
@Insert({"<script>" + "insert into table(message,status) values " + "<foreach item='item' index='index' collection='msgList' separator=','> " + "(#{item.message},#{item.status})" + "</foreach>" + "</script>"}) public int insertMsgBatch(@Param("msgList") List<Msg> msgList);
這樣就可以解決問題了,記錄一下