mybatis通过if+where、choose/when/otherwise、foreach等动态sql标签实现安全灵活的多条件查询:where自动处理and/or及冗余where;choose实现互斥条件分支;foreach支持in批量操作;需注意判空规范、避免${}拼接用户输入以防sql注入。

MyBatis 通过动态 SQL 标签(如 if、choose/when/otherwise、where、foreach 等)灵活拼接 SQL,实现多条件组合查询,避免手动拼接字符串带来的空值、多余 AND 或语法错误问题。
用 if + where 标签安全拼接条件
if 判断单个条件是否生效,where 标签自动处理开头的 AND/OR,并剔除无用的 WHERE 关键字(比如所有 if 都不满足时,不会生成多余的 WHERE)。
- 每个
<if test="xxx != null and xxx != ''"></if>控制一个字段是否参与查询 -
<where></where>替代硬编码的WHERE 1=1,更规范且防 SQL 注入风险(注意:test 表达式本身仍需校验,不能直接拼接用户输入) - 示例:查询用户,支持按 name、age、status 多选组合
<select id="listUsers" resulttype="User">
SELECT * FROM user
<where><if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if><if test="age != null">
AND age = #{age}
</if><if test="status != null">
AND status = #{status}
</if></where></select>
用 choose/when/otherwise 实现“多选一”逻辑
类似 Java 中的 switch-case,适用于互斥条件(例如:按 ID 查、按手机号查、按邮箱查,只生效其中一个)。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
<choose></choose>是外层容器,<when test="..."></when>是分支,<otherwise></otherwise>是默认分支 - 只会执行第一个匹配成功的
when,其余忽略;如果没有匹配,则执行otherwise - 常与
<where></where>搭配使用,保证 SQL 结构正确
<select id="getUserByCondition" resulttype="User">
SELECT * FROM user
<where><choose><when test="id != null">
id = #{id}
</when><when test="phone != null and phone != ''">
phone = #{phone}
</when><when test="email != null and email != ''">
email = #{email}
</when><otherwise>
1=0
</otherwise></choose></where></select>
用 foreach 处理 IN 查询或批量操作
当需要根据多个 ID 或状态值查询(如 IN (1,2,3)),用 <foreach></foreach> 动态展开集合。
-
collection指定传入参数中的集合名(如 list、array、map 中的 key) -
item是循环变量名,open/close/separator控制括号和分隔符 - 务必配合
<where></where>或显式 WHERE 子句,防止语法错误
<select id="listUsersByIds" resulttype="User">
SELECT * FROM user
WHERE id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach></select>
注意事项与避坑点
动态 SQL 强大但易出错,几个关键细节要留意:
- test 表达式中判空优先用
!= null和!= '',对 String 类型尤其要加非空字符串判断 - 避免在
<if></if>内写复杂逻辑,可提前在 Service 层做参数预处理(如把空字符串转为 null) - 数据库字段名、参数名大小写敏感,确保和实体类/Map 中的 key 一致
- SQL 注入风险仍在——
#{}是预编译安全的,但${}是字符串拼接,禁止用于用户输入字段名或表名
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










