#{}是预编译占位符,经PreparedStatement安全传参,防SQL注入;${}是字符串直接拼接,发生在MyBatis解析阶段,无预编译,存在注入风险,仅适用于动态表名、列名等语法片段且须白名单校验。

本质区别在于参数是否经过 SQL 预编译:`#{}` 是预编译占位符,走 JDBC 的 PreparedStatement 流程;`${}` 是纯字符串替换,发生在 MyBatis 解析 SQL 阶段,不进数据库预编译环节。
执行时机与 SQL 构建方式不同
MyBatis 处理 SQL 时,对 `#{}` 的处理分两步:先将所有 `#{xxx}` 替换为 ?,生成固定结构的 SQL(如 SELECT * FROM user WHERE id = ?),再把参数值通过 setLong()、setString() 等方法安全传入;而 `${}` 是在 XML 解析阶段就直接把变量值(比如 "order_name")原样拼进 SQL 字符串里,生成的是完整语句(如 ORDER BY order_name),之后直接交给数据库执行。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
安全性与 SQL 注入风险
- `#{}` 自动转义特殊字符,参数值不会参与 SQL 语法解析,完全杜绝注入
- `${}` 把用户输入直接嵌入 SQL,若传入
"id; DROP TABLE user--"这类恶意内容,就会被执行 - 字符串类型参数用 `${}` 时还必须手动加单引号,否则报错;`#{}` 会自动包裹引号和类型转换
适用场景有明确边界
- 用 `#{}`:所有“值”类参数——WHERE 条件、INSERT 字段值、UPDATE SET 子句中的新值
- 用 `${}`:仅限“SQL 结构片段”——动态表名、列名、排序字段(
ORDER BY ${sortField})、分组字段(GROUP BY ${groupCol})、UNION 子句等无法用 ? 占位的位置 - 注意:即使动态排序,也建议白名单校验 `${sortField}`,不能直接信任前端传参
性能与执行计划影响
`#{}` 生成的 SQL 模板固定,MySQL 可缓存执行计划,重复查询效率高;`${}` 每次参数不同就产生新 SQL(如 ORDER BY name 和 ORDER BY age 被视为两条不同语句),无法复用执行计划,还可能触发频繁 SQL 解析,增加数据库压力。

















