Java面试——MyBatis中#{}与${}的区别
{}能防止SQL注入而${}不能,因#{}走PreparedStatement预编译并安全绑定参数,${}是纯字符串替换、易被注入;${}仅限动态SQL结构(如表名、排序字段),须白名单校验。
为什么#{}能防止SQL注入而${}不能
根本原因在于 MyBatis 对两者的处理时机和方式不同:#{} 触发预编译(PreparedStatement),参数被当作占位符传入,数据库驱动自动做类型转换和转义;${} 是纯字符串替换,MyBatis 在 SQL 解析阶段就直接把变量值拼进 SQL 字符串里,不经过 JDBC 预编译流程。
比如 WHERE name = #{name} 最终生成的是 WHERE name = ?,再由 PreparedStatement.setString(1, "admin' --") 安全绑定;而 WHERE name = '${name}' 会直接变成 WHERE name = 'admin' --',注释掉后续条件,造成注入漏洞。
哪些场景必须用${},又该怎么控风险
${} 唯一合理用途是动态拼接 **SQL 结构部分**,比如表名、列名、ORDER BY 子句、LIMIT 参数(非数值上下文)——这些都不能用 ? 占位。
- 表名动态:用
FROM ${tableName},但必须白名单校验tableName值,例如只允许"user"、"order"等枚举值 - 排序字段:用
ORDER BY ${sortColumn} ${sortOrder},sortColumn必须从固定字段列表中取(如"id","create_time"),sortOrder限制为"ASC"或"DESC" - 避免在
${}中拼接用户输入的任意字符串,尤其是带单引号、分号、注释符的内容
#{id} 和 ${id} 在参数类型为数字时表现一样?
表面上看都“能运行”,但行为完全不同:
-
WHERE id = #{id}→ JDBC 绑定为setLong(1, 123),类型安全,支持 null 处理(setNull) -
WHERE id = ${id}→ 直接替换为WHERE id = 123,如果id是 null,会拼出WHERE id = null,语法错误或逻辑异常 - 若
id是字符串类型(如"123' OR '1'='1"),${id}会直接触发注入,#{id}则作为字符串字面量安全绑定
MyBatis Plus 的 Wrapper 是否也遵循这套规则
是的,QueryWrapper 和 UpdateWrapper
底层仍走 MyBatis 的 SQL 构建逻辑。它默认所有条件方法(如 eq("name", value))都使用 #{} 语义;但当你调用 apply("age > {0}", 18) 或 last("LIMIT 1") 时,就进入了 ${} 类似的行为域——apply 中的 {0} 是模板占位,实际仍可能拼接原始字符串,务必确保传入的参数已过滤或来自可信源。
更稳妥的做法是:优先用 gt("age", 18) 这类类型安全方法;非要用 apply 拼 SQL 片段时,对变量值做正则校验(如 ^\d+$ 匹配纯数字)。
SELECT * FROM ${tableName} WHERE status = #{status} ORDER BY ${sortBy} ${sortOrder}真正危险的不是语法本身,是把本该由数据库驱动处理的参数,交给人肉字符串拼接来承担。只要涉及用户输入,${} 就得过白名单或格式校验这一关——漏掉一次,就可能让整张表裸奔。
上一篇 : Go语言如何实现WebSocket通信_WebSocket基础用法
下一篇 : 支付宝生活号商城怎么查快递单号_支付宝生活号商城查单号方法【解析】
-
SEO外包最佳选择国内专业的白帽SEO机构,熟知搜索算法,各行业企业站优化策略!
SEO公司
-
可定制SEO优化套餐基于整站优化与品牌搜索展现,定制个性化营销推广方案!
SEO套餐
-
SEO入门教程多年积累SEO实战案例,从新手到专家,从入门到精通,海量的SEO学习资料!
SEO教程
-
SEO项目资源高质量SEO项目资源,稀缺性外链,优质文案代写,老域名提权,云主机相关配置折扣!
SEO资源
-
SEO快速建站快速搭建符合搜索引擎友好的企业网站,协助备案,域名选择,服务器配置等相关服务!
SEO建站
-
快速搜索引擎优化建议没有任何SEO机构,可以承诺搜索引擎排名的具体位置,如果有,那么请您多注意!专业的SEO机构,一般情况下只能确保目标关键词进入到首页或者前几页,如果您有相关问题,欢迎咨询!