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

MyBatis 中 #{} 與 ${} 參數傳遞差異深度解析

     編輯:Java 相關知識

核心差異概覽

在 MyBatis 中,#{} 和 ${} 是兩種截然不同的參數替換機制,正確理解它們的區別對於編寫安全、高效的 SQL 至關重要。

#{}:預編譯參數化(推薦默認使用)

  • 機制:採用 JDBC PreparedStatement 預編譯機制,參數佔位符為 ?
  • 處理方式:將傳入參數視為字符串,自動添加引號轉義
  • SQL 注入防護:有效防止 SQL 注入攻擊
  • 適用場景:WHERE 條件值、INSERT/UPDATE 字段值等數據參數

實例演示

// Mapper XML
select * from user where name = #{name}

// 傳入參數:name = "張三"
// 實際執行 SQL:
select * from user where name = '張三'

// 傳入參數包含單引號:name = "O'Reilly"
// 實際執行 SQL(自動轉義):
select * from user where name = 'O\'Reilly'

${}:直接字符串替換(慎用)

  • 機制:簡單的字符串替換,類似模板引擎,直接拼接到 SQL 中
  • 處理方式:原樣輸出參數值,不添加引號,不進行轉義
  • 安全風險:無法防止 SQL 注入,存在安全隱患
  • 適用場景:數據庫對象名(表名、列名)、排序字段、分頁關鍵字等非數據值部分

實例演示

// Mapper XML
select * from ${tableName} order by ${columnName} ${sortOrder}

// 傳入參數:tableName="user", columnName="create_time", sortOrder="DESC"
// 實際執行 SQL:
select * from user order by create_time DESC

關鍵場景對比:ORDER BY 排序

這是最常見的必須使用 ${} 的場景:

// 錯誤寫法(使用 #{})
select * from user order by #{columnName}
// 實際 SQL:select * from user order by 'create_time' -- 無效,視為字符串常量

// 正確寫法(使用 ${})
select * from user order by ${columnName}
// 實際 SQL:select * from user order by create_time -- 有效,視為列名

# 與 $ 的歷史淵源(iBATIS 時代)

早期 iBATIS 使用 #property# 和 $property$ 語法,MyBatis 3.x 改為 #{} 和 ${},但核心原理未變:

特性# / #{}$ / ${}
參數處理視為字符串,自動加引號直接顯示生成在 SQL 中
輸入 111解析為 "111"解析為 111
輸入 id解析為 "id"解析為 id
SQL 注入防護強無
主要用途數據值參數數據庫對象、SQL 片段

最佳實踐原則

  1. 默認使用 #{}:除非有明確理由,所有數據值參數均使用 #{}
  2. 必要時使用 ${}:僅在動態表名、列名、排序字段、分頁關鍵字等場景使用
  3. 嚴格驗證 ${} 參數:若必須使用 ${},務必在業務層對參數進行白名單驗證,杜絕用戶輸入直接拼接
  4. 代碼審查重點:Code Review 時重點檢查 ${} 使用場景是否合理、是否有防注入措施

官方文檔警示

「接受用戶輸入內容並直接提供給語句中不變的字符串是不安全的,會導致潛在的 SQL 注入攻擊。因此你不應該允許用戶輸入這些字段,或者自行轉義並驗證。」

總結

#{} 是參數化查詢的標準方式,提供安全性與性能;${} 是字符串模板替換,僅用於 SQL 結構動態構建。記住口訣:「能用 # 就不用 $,用 $ 必驗證」。

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