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

在 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");
}
相关推荐
不光头强1 分钟前
shiro学习要点
java·学习·spring
工一木子4 分钟前
Java 的前世今生:从 Oak 到现代企业级语言
java·开发语言
H Journey9 分钟前
Linux su 命令核心用法总结
java·linux·服务器·su
小学仔31 分钟前
科大镜像科大镜像科大镜像
java
小旭952731 分钟前
Java 反射详解
java·开发语言·jvm·面试·intellij-idea
HalvmånEver34 分钟前
Linux:线程创建与终止上(线程五)
java·linux·jvm
有来技术40 分钟前
ASP.NET Core 权限管理系统(RBAC)设计与实现|vue3-element-admin .NET 后端
vue.js·后端·c#·asp.net·.net
m0_7482331741 分钟前
PHP版本演进:从7.x到8.x全解析
java·开发语言·php
qq_124987075342 分钟前
基于springboot的林业资源管理系统设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
当战神遇到编程1 小时前
图书管理系统
java·开发语言·单例模式