首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

MyBatis #{} 與 ${} 關鍵差異:預編譯參數 vs 字符串替換,一個 Bug 引發的深度思考

     編輯:Java 綜合教學

核心結論

  • #{param} → **預編譯參數標記**(?),防 SQL 注入,類型安全
  • ${param} → **純字符串替換**,動態 SQL 解析階段直接拼接,不防注入

實戰 Bug 還原

場景

前端傳入多選參數 ruleName=A,B,C,業務層處理為 'A','B','C' 字符串,Mapper 中需用 IN 查詢。

錯誤寫法

<if test="ruleName != null and ruleName != ''">
    AND a.rule_name IN (#{ruleName})
</if>

生成 SQL:

... AND a.rule_name IN (?) ...

參數綁定:'A','B','C' 作為單個字符串綁定到唯一佔位符,導致查詢無結果或報錯。

正確寫法

<if test="ruleName != null and ruleName != ''">
    AND a.rule_name IN (${ruleName})
</if>

生成 SQL:

... AND a.rule_name IN ('A','B','C') ...

字符串直接內嵌到 SQL,IN 子句語法正確。

底層機制對比

維度#{}${}
解析階段預編譯前(BoundSql)動態 SQL 解析階段
生成內容? 佔位符變量值直接拼接
類型處理TypeHandler 自動轉換調用 toString()
SQL 注入防護無防護,極高風險
適用場景WHERE 條件值、INSERT/UPDATE 值表名、列名、排序欄位、IN 列表等結構性動態

最佳實踐原則

  1. 默認用 #{},90%+ 場景適用
  2. 只在無法用佔位符時(表名、列名、IN 列表、ORDER BY 欄位)用 ${}
  3. 使用 ${} 時必須嚴格驗證/白名單過濾輸入,防注入
  4. IN 列表優選:MyBatis foreach 標籤 + #{},兼具安全與動態

foreach 替代方案(推薦)

<foreach collection="nameList" item="name" open="(" separator="," close=")">
    #{name}
</foreach>

生成 IN (?,?,?),參數逐個綁定,完全安全。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved