在上篇文章給大家介紹了Mybatis中#{}和${}傳參的區別及#和$的區別小結,如果大家有需要可以參考下。
$和#簡單說明:
#相當於對數據加上雙引號,$相當於直接顯示數據。
一、總結
mybatis中使用sqlMap進行sql查詢時,經常需要動態傳遞參數。動態SQL是mybatis的強大特性之一,也是它優於其他ORM框架的一個重要原因。 mybatis在對sql語句進行預編譯之前,會對sql進行動態解析,解析為一個BoundSql對象,也是在此處對動態SQL進行處理的。在動態SQL 解析階段,#{ }和${ }會有不同的表現,#{ }解析為一個JDBC預編譯語句(prepared statement)的參數標記符。
一個#{ } 被解析為一個參數佔位符? 。 ${ } 僅僅為一個純碎的string 替換,在動態SQL 解析階段將會進行變量替換。
二、Bug描述
前端傳入參數:
skip:0
take:10
ruleName:A,B,C
業務層處理:
package SQL;/*** 將前端多選參數轉義為SQL語句內容*/public class SQLUtil {private final static String REPLACECHAR_COMMA = ",";private final static String REPLACECHAR_SEMICOLON = ";";public static void main(String[] args) {String s1 = "A,B,C";String s2 = "ABC";System.out.println("逗號分隔:" + formatInStr(s1));System.out.println("空格分隔:" + formatInStr(s2));}private static String formatInStr(String queryStr) {return queryInStr(sliptQueryStr(queryStr));}private static String[] sliptQueryStr(String queryStr) {if (null == queryStr || "".equals(queryStr.trim())) return null;queryStr = queryStr.replaceAll(SQLUtil.REPLACECHAR_COMMA, " ").replaceAll(REPLACECHAR_SEMICOLON, " ");return queryStr.split("//s+");}private static String queryInStr(String[] queryStrs) {if (null == queryStrs || 0 == queryStrs.length) return null;StringBuffer buf = new StringBuffer();for (int i = 0; i < queryStrs.length; i++) {if (i != 0) buf.append(",");buf.append("'").append(queryStrs[i]).append("'");}return buf.toString();}} Mapper層處理:
//錯誤的處理<if test="ruleName != null and ruleName != ''">AND a.rule_name IN (#{ruleName})</if>//正確的處理<if test="ruleName != null and ruleName != ''">AND a.rule_name IN (${ruleName})</if>日誌描述:
[DEBUG] [2016-08-02 17:42:42.226] [qtp1457334982-157] java.sql.Connection - ==> Preparing: SELECT a.id, a.is_valid, a.rule_lable, a.rule_name, a.type, b.sp_id, b.sp_name, a.rule_content, c.user_name, a.gmt_modified, a.ordering FROM idc_logistics_assign_rules a LEFT JOIN app_user c on c.work_no=a.modifier and c.is_deleted='n', idc_sp_info b WHERE a.is_deleted = 'n' AND b.is_deleted = 'n' AND a.sp_id = b.sp_id AND a.rule_name IN (?) ORDER BY ordering asc limit ?, ? [DEBUG] [2016-08-02 17:42:42.226] [qtp1457334982-157] java.sql.PreparedStatement - ==> Parameters: 'A','B'(String), 0(Integer), 10(Integer)
結果分析:mapper層對sql有預編譯處理,對於#有佔位符? ,但是對於$會直接替換。
PS:MyBatis排序時使用order by 動態參數時需要注意,用$而不是#
字符串替換
默認情況下,使用#{}格式的語法會導致MyBatis創建預處理語句屬性並以它為背景設置安全的值(比如?)。這樣做很安全,很迅速也是首選做法,有時你只是想直接在SQL語句中插入一個不改變的字符串。比如,像ORDER BY,你可以這樣來使用:
複製代碼代碼如下:
ORDER BY ${columnName}
這裡MyBatis不會修改或轉義字符串。
重要:接受從用戶輸出的內容並提供給語句中不變的字符串,這樣做是不安全的。這會導致潛在的SQL注入攻擊,因此你不應該允許用戶輸入這些字段,或者通常自行轉義並檢查。