MyBatis order by失效問題

帥 可敵國發表於2020-11-04

MyBatis order by失效問題
需求:
業務模組中所有列表的欄位均可以排序
方案:前端將要排序的欄位及排序規則傳給後臺,後臺進行拼接,然後組裝進SQL
因為前後端欄位都是駝峰法命名,資料庫欄位是下劃線命名,所以這裡有一個排序欄位轉換
轉換程式碼:

    public static String camel4underline(String param){
        Pattern p=Pattern.compile("[A-Z]");
        if(param==null ||param.equals("")){
            return "";
        }
        StringBuilder builder=new StringBuilder(param);
        Matcher mc=p.matcher(param);
        int i=0;
        while(mc.find()){
            builder.replace(mc.start()+i, mc.end()+i, "_"+mc.group().toLowerCase());
            i++;
        }
        if('_' == builder.charAt(0)){
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }

查詢xml:

  <select id="selectByItemId"  resultMap="BaseResultMap">
    select 
    MATTER_ID, ITEM_ID, FILE_ID, ITEM_CODE, MATTER, MATTER_STATE, REMARK, MATTER_DATE, CREATED_BY, CREATED_TIME, UPDATED_BY, PDATED_TIME,MATTER_TYPE      
    from T_PLAN_OUT_MATTER_RGT
    where ITEM_ID= #{itemId,jdbcType=VARCHAR}
    <if test="timeStart!=null">
      AND MATTER_DATE>=#{timeStart,jdbcType=VARCHAR}
    </if>
    <if test="timeEnd!=null">
       AND MATTER_DATE <![CDATA[<=]]> #{timeEnd,jdbcType=VARCHAR}
    </if>
    <if test="likeName!=null">
      AND (MATTER like  concat(concat('%',#{likeName,jdbcType=VARCHAR}),'%')   or REMARK like  concat(concat('%',#{likeName,jdbcType=VARCHAR}),'%') )
    </if>
    <if test="matterType!=null">
      AND MATTER_TYPE =#{matterType,jdbcType=VARCHAR}
    </if>
    <choose>
      <when test="sortRule != null">
        ORDER BY  #{sortRule}
      </when>
      <otherwise>
        ORDER BY MATTER_DATE ASC,MATTER_ID ASC
      </otherwise>
    </choose>
  </select>

問題
控制檯列印出的SQL語句是正確的,但是排序沒生效
解決:
(1)#運算子,Mybatis會將傳入的物件當成一個字串,在進行變數替換時會加上引號
比如sortRule=“CREATED_TIME DESC NULLS LAST”, sql語句是
ODERR BY “CREATED_TIME DESC NULLS LAST”
正常語句應該是不要雙引號的
(2)不用#,使用$運算子,Mybatis不會進行預編譯,直接把值傳進去,無法防止sql注入,所以應修改為:

    <choose>
      <when test="sortRule != null">
        ORDER BY  ${sortRule}
      </when>
      <otherwise>
        ORDER BY MATTER_DATE ASC,MATTER_ID ASC
      </otherwise>
    </choose>

要避免SQL隱碼攻擊隱患可以使用列舉,但是我這種需求是不合適用列舉的

最後來總結下#和$
1.預編譯(#)sql有快取作用,非預編譯($)沒有
預編譯(#)一次編譯、多次執行,省去了解析優化等過程;此外預編譯語句能防止sql注入。
2. $ 方式一般用於傳入資料庫物件,例如傳入表名、排序規則等

一般能用#的就別用$。

相關文章