#和$符号使用场景 注意事项

在 MyBatis 中,$# 的区别很关键,关系到 SQL 注入风险和 SQL 的动态拼接方式。其中:什么时候 $ 不能换成 #,什么时候能换?


一、先简单回顾一下 $# 的区别:

  • #安全的参数替换方式 ,使用预编译机制,会将参数作为占位符传给数据库,避免 SQL 注入。

    sql 复制代码
    SELECT * FROM user WHERE name = #{name}

    最终执行的是:

    sql 复制代码
    SELECT * FROM user WHERE name = ?

    然后由 JDBC 设置参数。

  • $直接文本替换 ,是在 SQL 语句生成阶段将参数原样拼接 进 SQL 中,容易引起 SQL 注入

    sql 复制代码
    SELECT * FROM user ORDER BY ${column}

    如果 column = "name",最终 SQL 是:

    sql 复制代码
    SELECT * FROM user ORDER BY name

二、不能直接用 # 替换 $ 的情况(即必须用 $):

这些都是必须动态拼接 SQL 结构或关键字的情况:

  1. 动态字段名或表名

    sql 复制代码
    SELECT ${column} FROM ${table}
    • 你不能写成 #{column},因为数据库不允许字段名或表名是占位符。
    • 表名/字段名不能作为参数预编译处理,只能拼接进去。
  2. 动态排序

    bash 复制代码
    ORDER BY ${sortField} ${sortOrder}
    • 如果用 #,会变成语法错误,SQL 无法执行。
  3. 动态 where 条件字段

    bash 复制代码
    WHERE ${field} = #{value}
    • 字段名不能预编译,因此必须用 ${field}

三、可以用 # 替换 $ 的情况:

  • 凡是值的部分(常规参数)都应该使用 #,而不是 $

    bash 复制代码
    WHERE id = #{id}
    AND name = #{name}
    AND created_at >= #{startTime}

只要不是拼接字段名、表名、排序等 SQL 结构,基本都可以用 #


四、小结

使用场景 推荐用法 原因说明
字段值 / 参数值 #{} 安全,防止 SQL 注入
字段名 / 表名 ${} 不能使用预编译,只能拼接
动态排序字段 / 顺序 ${} 语法需要拼接关键字
拼接完整 where 子句 ${} 需要直接拼接结构(如多个条件)

五、安全建议

如果你必须使用 ${} ,一定要白名单校验输入值,避免 SQL 注入风险。

比如:

arduino 复制代码
if (!ALLOWED_COLUMNS.contains(sortField)) {
    throw new IllegalArgumentException("Invalid column");
}
相关推荐
追逐时光者2 小时前
一款使用 C# 编写专为 Windows 11 打造的文件资源管理器增强工具!
后端·.net
风象南2 小时前
普通人用AI加持赚到的第一个100块
人工智能·后端
皮皮林5514 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河4 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
JavaGuide7 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
桦说编程7 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
格砸8 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端
蝎子莱莱爱打怪8 小时前
GitLab CI/CD + Docker Registry + K8s 部署完整实战指南
后端·docker·kubernetes
躺平大鹅9 小时前
Java面向对象入门(类与对象,新手秒懂)
java