{}是MyBatis防SQL注入唯一默认机制,所有数据值必须用#{}转为预编译占位符;LIKE需Java层拼接或数据库函数;动态结构如ORDER BY须白名单校验后才可用${};IN查询须用<foreach>标签。

用 #{} 传参是 MyBatis 防 SQL 注入最直接、最可靠的方式——它不是“辅助手段”,而是唯一应作为默认选择的参数绑定机制。核心在于:所有用户可控的输入值,必须走 #{ },绝不能图方便用 ${ } 拼接。
所有值类参数一律用 #{}
只要参数代表的是“数据内容”,而非“SQL 结构”,就必须用 #{ }。MyBatis 会将其转为 JDBC 的 ? 占位符,由数据库驱动安全填充,自动加引号、转义单引号、处理类型,完全隔离语法污染。
- WHERE 条件:
username = #{username}、status IN (#{s1}, #{s2}) - INSERT 值:
VALUES (#{name}, #{age}, #{email}) - UPDATE 赋值:
SET phone = #{phone}, updated_at = NOW() - DELETE 条件:
WHERE id = #{id} AND tenant_id = #{tenantId}
LIKE 模糊查询不能写成 '%${keyword}%'
在 #{} 外直接加 % 是无效的(如 LIKE '%#{keyword}%' 会报错),而用 ${} 拼接则等于放弃防护。正确做法只有两种:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Java 层拼通配符:Service 中传参前处理,
mapper.search("%" + keyword + "%"),XML 中仍写username LIKE #{keyword} -
数据库函数兜底:MySQL 用
CONCAT('%', #{keyword}, '%');Oracle/PostgreSQL 用'%' || #{keyword} || '%'
动态结构(排序、表名等)必须白名单校验后才可用 ${}
ORDER BY 字段、分表后缀、GROUP BY 表达式这些属于 SQL 语法组成部分,无法用 #{ } 绑定。此时若必须用 ${ },前提是严格校验输入是否在预设白名单中:
立即学习“Java免费学习笔记(深入)”;
- 定义合法字段集:
Set.of("id", "create_time", "status") - 接收参数后立即校验:
if (!ALLOWED_SORT_FIELDS.contains(sortField)) throw new IllegalArgumentException(); - 校验通过后再拼入:
ORDER BY ${sortField} ${order}(order 同样需校验 ASC/DESC)
IN 查询多个值要用 <foreach> 标签
不能写 WHERE id IN (${ids})(危险拼接)或 WHERE id IN (#{ids})(类型不匹配)。正确方式是让每个元素独立走预编译:
- Mapper 接口传
List<Long> ids - XML 中:
WHERE id IN <foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>

















