springboot mybatis常見異常及處理方法


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);

這樣就可以解決問題了,記錄一下

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM