首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MyBatis 中 #{} 與 ${} 的核心區別與最佳實踐

     編輯:程式設計疑難解答

一句話總結

#{} 是參數佔位符(預編譯),${} 是字符串拼接(直接替換)。前者防 SQL 注入,後者用於動態表名/列名/排序字段等無法預編譯的場景。

詳細對比

特性#{param}${param}
處理機制JDBC 預編譯 PreparedStatement,參數化查詢SQL 解析前直接進行字符串替換
SQL 注入防護✅ 完全防護,參數視為純數據❌ 無防護,輸入會成為 SQL 一部分
適用場景WHERE 條件值、INSERT/UPDATE 值、IN 列表值等動態表名、列名、ORDER BY 字段、數據庫函數名等
類型處理自動處理類型轉換、引號轉義需手動確保類型匹配、加引號(字符串)
性能可利用數據庫執行計劃緩存無法複用執行計劃,頻繁變化會增加解析開銷

代碼示例

安全用法:#{}

<select id="selectUser" resultType="User">
  SELECT * FROM users WHERE username = #{username} AND status = #{status}
</select>

<!-- 對應 Java: selectUser("admin', '1=1--", 1) 生成 SQL -->
<!-- SELECT * FROM users WHERE username = ? AND status = ? -->
<!-- 參數: ["admin', '1=1--", 1] 安全! -->

動態結構用法:${}

<select id="selectByPage" resultType="User">
  SELECT * FROM ${tableName}
  WHERE status = #{status}
  ORDER BY ${orderColumn} ${orderDirection}
  LIMIT #{offset}, #{pageSize}
</select>

<!-- 調用: selectByPage({tableName:"users", orderColumn:"create_time", orderDirection:"DESC", status:1, offset:0, pageSize:10}) -->
<!-- 生成: SELECT * FROM users WHERE status = ? ORDER BY create_time DESC LIMIT ?, ? -->

⚠️ ${} 使用安全規範(必讀)

  1. 嚴禁 直接拼接用戶未經驗證的輸入(如前端傳來的排序字段)。
  2. 白名單校驗:在 Mapper 方法或 Service 層對 ${} 參數進行嚴格白名單過濾。
    public List<User> selectByPage(QueryParam param) {
        // 白名單校驗
        Set<String> allowedColumns = Set.of("id", "username", "create_time", "update_time");
        if (!allowedColumns.contains(param.getOrderColumn())) {
            throw new IllegalArgumentException("非法排序字段");
        }
        // 方向校驗
        if (!"ASC".equalsIgnoreCase(param.getOrderDirection()) && !"DESC".equalsIgnoreCase(param.getOrderDirection())) {
            param.setOrderDirection("ASC");
        }
        return mapper.selectByPage(param);
    }
  3. 日誌脫敏:開啟 MyBatis 日誌時,${} 替換後的完整 SQL 會打印,注意敏感數據洩露風險。

進階:IN 子句的正確處理

MyBatis 提供 <foreach> 標籤配合 #{} 完美解決 IN 列表問題:

<select id="selectByIds" resultType="User">
  SELECT * FROM users WHERE id IN
  <foreach collection="ids" item="id" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

總結建議

  • 默認使用 #{},覆蓋 95% 以上場景。
  • 僅在必須動態指定 SQL 結構元素時 使用 ${},並嚴格實施白名單校驗。
  • 代碼審查時,重點檢查所有 ${} 使用點的安全性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved