MyBatis中#{}用于传数据值(如WHERE、INSERT、UPDATE、LIKE中的参数),通过PreparedStatement预编译防SQL注入;${}仅用于传SQL结构(如表名、列名、ORDER BY字段),必须经白名单校验确保可信。

用 #{} 传值,用 ${} 传结构 —— 这是 MyBatis 参数传递最本质的分工。
什么时候必须用 #{}
所有需要传「数据值」的地方,都该用 #{}。它会走 PreparedStatement 预编译,自动加引号、转义特殊字符、防 SQL 注入。
- WHERE 条件中的字段匹配(如
name = #{name}) - INSERT 的 VALUES 值(如
VALUES(#{username}, #{age})) - UPDATE 的 SET 字段(如
SET status = #{status}) - LIKE 模糊查询(如
username LIKE CONCAT('%', #{keyword}, '%'))
什么时候只能用 ${}
${} 是字符串原样替换,不经过预编译,所以只适用于数据库对象名或 SQL 关键字这类「语法成分」——它们不能被当作参数值处理。
- 动态表名(如
SELECT * FROM ${tableName}) - 动态列名(如
SELECT ${columnName} FROM user) - ORDER BY 字段和方向(如
ORDER BY ${sortField} ${sortOrder}) - GROUP BY 或 HAVING 中的动态字段(如
GROUP BY ${groupColumn})
⚠️ 注意:用 ${} 时,必须确保传入内容可信(比如来自配置项、白名单枚举),绝不能直接拼接用户输入。
立即学习“Java免费学习笔记(深入)”;
常见踩坑点
这些写法看似能跑通,但藏着严重风险或逻辑错误:
-
WHERE name = '${name}'—— 手动加引号也不安全,恶意输入仍可绕过(如admin' --) -
ORDER BY #{sortField}—— 报错!#{} 无法注入列名,MySQL 会把 ? 当作字面量值而非标识符 -
IN 子句用 ${ids}—— 危险且低效;正确做法是用<foreach>配合 #{item} - 把 ${} 用于数值类型却漏掉引号(如
id = ${id}对 String 类型会报错)
一句话判断口诀
你想填进去的是「数据内容」?→ 用 #{}。
你想填进去的是「SQL 里哪张表、哪个字段、怎么排序」?→ 用 ${},并做好来源校验。


















