| 語法 | 處理方式 | SQL 生成示例 | 安全性 | 典型場景 |
|---|---|---|---|---|
#{param} | 預編譯參數化(PreparedStatement),自動加引號、轉義 | WHERE id = ? → WHERE id = '111' | ✅ 防 SQL 注入 | 90%+ 參數傳遞(WHERE 值、INSERT 值等) |
${param} | 字串直接替換(Statement),原樣拼接進 SQL | ORDER BY ${col} → ORDER BY create_time | ❌ 風險:需自行驗證/轉義 | 動態表名、欄位名、排序欄位、分庫分表後綴 |
PreparedStatement,參數佔位符 ?,由 JDBC 驅動完成型別轉換與特殊字元轉義,徹底阻斷注入攻擊面。#{} 絕不使用 ${}。ORDER BY ${sortColumn} 必須用 ${},但需在 Service 層建立白名單驗證 sortColumn 僅允許合法欄位名。SELECT * FROM ${tablePrefix}_user,同樣需嚴格校驗前綴合法性。WHERE name LIKE CONCAT('%', #{keyword}, '%') 使用 #{},而非 WHERE name LIKE '%${keyword}%'。SqlSourceBuilder 解析階段:#{} 生成 ParameterMapping 註冊至 BoundSql;${} 直接替換 sqlSource 原始字串。運行期 DefaultParameterHandler 僅處理 ParameterMapping 列表,${} 替換結果不可控。
任何接受使用者輸入並直接置入 ${} 的場景,均構成 SQL 注入高危隱患。必須實施:白名單校驗、長度限制、特殊字元過濾、權限最小化(僅 SELECT 權限)。