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

在 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");
}
相关推荐
Full Stack Developme5 分钟前
jdk.random 包详解
java·开发语言·python
懒羊羊不懒@9 分钟前
Java基础入门
java·开发语言
程序员小假1 小时前
我们来说一说 Redisson 的原理
java·后端
chirrupy_hamal1 小时前
网络编程 - TCP 篇
java
白衣鸽子1 小时前
数据库高可用设计的灵魂抉择:CAP权衡
数据库·后端
xyy1231 小时前
SixLabors.ImageSharp 使用指南
后端
notillusion1 小时前
KWW#71843
java·php·程序优化
Deschen2 小时前
设计模式-抽象工厂模式
java·设计模式·抽象工厂模式
齐木卡卡西在敲代码2 小时前
java流式编程学习
java
阑梦清川2 小时前
docker部署tomcat和nginx
后端