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

MyBatis #{ } 與 ${ } 差異深度解析與實戰避坑指南

     編輯:Java 相關知識

核心差異一覽

語法處理階段SQL 形式安全性適用場景
#{param}預編譯階段WHERE name = ? (PreparedStatement)高 (防 SQL 注入)一般參數傳遞、WHERE 條件、INSERT/UPDATE 值
${param}動態 SQL 解析階段WHERE name = 'value' (字串直接替換)低 (有注入風險)動態表名、欄位名、排序欄位、IN 子句動態列表

實戰案例:IN 子句踩坑記

錯誤寫法

<!-- 前端傳入 ruleName = "A,B,C" -->
<if test="ruleName != null and ruleName != ''">
    AND a.rule_name IN (#{ruleName})
</if>

MyBatis 會將整個字串 'A,B,C' 視為單一參數綁定到 ?,產生的 SQL 類似:

SELECT ... WHERE a.rule_name IN (?) -- 參數為 'A,B,C'

資料庫會嘗試找 rule_name = 'A,B,C' 的資料,導致查無結果。

正確寫法

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

配合 Service 層將字串轉為 'A','B','C' 格式:

public String formatInStr(String input) {
    if (input == null || input.trim().isEmpty()) return null;
    String[] arr = input.replaceAll("[,;]", " ").split("\\s+");
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < arr.length; i++) {
        if (i > 0) sb.append(",");
        sb.append("'").append(arr[i]).append("'");
    }
    return sb.toString(); // 回傳 'A','B','C'
}

最終 SQL 變為:

SELECT ... WHERE a.rule_name IN ('A','B','C')

其他常見 ${ } 用途

  • 動態排序:ORDER BY ${sortColumn} ${sortOrder}
  • 動態表名:SELECT * FROM ${tablePrefix}_user
  • 指定欄位:SELECT ${columns} FROM table

安全性警示 ⚠️

絕對不可將未經驗證的使用者輸入直接放入 ${ }。這會造成 SQL 注入漏洞。
必須在 Service 層對輸入進行嚴格白名單驗證(如欄位名必須在允許清單中),或自行構建安全字串後再傳入。

總結

  • 預設使用 #{ },享受預編譯效能與安全性。
  • 只有在「SQL 結構本身需動態變化」時(表名、欄位名、排序、IN 列表),才考慮 ${ }。
  • 使用 ${ } 時,務必在 Java 端完成嚴格的輸入驗證與轉義。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved