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

在 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");
}
相关推荐
我是咸鱼不闲呀10 分钟前
力扣Hot100系列22(Java)——[图论]总结(岛屿数量,腐烂的橘子,课程表,实现Trie(前缀树))
java·leetcode·图论
1104.北光c°10 分钟前
深入浅出 Elasticsearch:从搜索框到精准排序的架构实战
java·开发语言·elasticsearch·缓存·架构·全文检索·es
MSTcheng.16 分钟前
【优选算法必修篇——位运算】『面试题 01.01. 判定字符是否唯一&面试题 17.19. 消失的两个数字』
java·算法·面试
蹦哒18 分钟前
Kotlin 与 Java 语法差异
java·python·kotlin
SmartBrain19 分钟前
Spring Boot的高性能技术栈的工程实践
spring boot·后端·架构
左左右右左右摇晃19 分钟前
Java并发——并发编程底层原理
java·开发语言
一个有温度的技术博主25 分钟前
Redis系列八:Jedis连接池在java中的使用
java·redis·bootstrap
cyforkk27 分钟前
Java 并发编程教科书级范例:深入解析 computeIfAbsent 与方法引用
java·开发语言
后青春期的诗go29 分钟前
泛微OA-E9与第三方系统集成开发企业级实战记录(八)
java·接口·金蝶·泛微·oa·集成开发·对接
dreamxian34 分钟前
苍穹外卖day09
java·spring boot·tomcat·log4j·maven