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

MyBatis #{} 與 ${} 核心差異深度解析:預編譯防注入與動態 SQL 場景選型

     編輯:Java 綜合教學

核心機制對比

語法處理方式SQL 生成示例安全性典型場景
#{param}預編譯參數化(PreparedStatement),自動加引號、轉義WHERE id = ? → WHERE id = '111'✅ 防 SQL 注入90%+ 參數傳遞(WHERE 值、INSERT 值等)
${param}字串直接替換(Statement),原樣拼接進 SQLORDER BY ${col} → ORDER BY create_time❌ 風險:需自行驗證/轉義動態表名、欄位名、排序欄位、分庫分表後綴

原理解析

  • #{}:MyBatis 生成 PreparedStatement,參數佔位符 ?,由 JDBC 驅動完成型別轉換與特殊字元轉義,徹底阻斷注入攻擊面。
  • ${}:屬於 OGNL 表達式字串替換,在 SQL 解析前完成文本替換,等同於動態拼接 SQL 字串,繞過預編譯機制。

實戰決策指南

  1. 原則:能用 #{} 絕不使用 ${}。
  2. 排序場景:ORDER BY ${sortColumn} 必須用 ${},但需在 Service 層建立白名單驗證 sortColumn 僅允許合法欄位名。
  3. 動態表名:SELECT * FROM ${tablePrefix}_user,同樣需嚴格校驗前綴合法性。
  4. Like 模糊查詢:WHERE name LIKE CONCAT('%', #{keyword}, '%') 使用 #{},而非 WHERE name LIKE '%${keyword}%'。

原始碼層面印證

SqlSourceBuilder 解析階段:#{} 生成 ParameterMapping 註冊至 BoundSql;${} 直接替換 sqlSource 原始字串。運行期 DefaultParameterHandler 僅處理 ParameterMapping 列表,${} 替換結果不可控。

安全警示

任何接受使用者輸入並直接置入 ${} 的場景,均構成 SQL 注入高危隱患。必須實施:白名單校驗、長度限制、特殊字元過濾、權限最小化(僅 SELECT 權限)。

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