mybatis 的 标签能自动去除开头多余的 and/or,是因为它仅在内部有非空子标签时才添加 where,并智能截断每个以 and 或 or 开头的 sql 片段前缀;要求动态条件必须显式以 and/or 开头才能被识别剥离。

MyBatis 的 <where></where> 标签会自动处理 SQL 中动态条件开头多余的 AND 或 OR,核心在于它只在内部有至少一个子标签(如 <if></if>)返回非空内容时才插入 WHERE 关键字,并且会智能地去掉第一个匹配条件前的多余逻辑运算符。
为什么 <where></where> 能去掉开头的 AND/OR
它不是简单地“删掉第一个 AND”,而是通过解析内部每个子标签生成的 SQL 片段:如果某个 <if></if> 生成了以 AND 或 OR 开头的字符串,<where></where> 会识别并截断该前缀;同时,整个标签只在有内容时才补上 WHERE 关键字。
必须配合以 AND/OR 开头的条件写法
要让 <where></where> 生效,每个动态条件内部的 SQL 必须显式以 AND 或 OR 开头,否则无法被识别和剥离:
- ✅ 正确写法:
<if test="name != null">AND name = #{name}</if> - ✅ 正确写法:
<if test="age > 0">AND age > #{age}</if> - ❌ 错误写法:
<if test="name != null">name = #{name}</if>(没加 AND,<where></where>不会做任何剥离)
实际使用示例
比如查询用户,支持按姓名、年龄、状态动态筛选:
<select id="selectUsers" resulttype="User">
SELECT * FROM user
<where><if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null and age > 0">AND age = #{age}</if><if test="status != null">AND status = #{status}</if></where></select>
当只有 name 有值时,最终 SQL 是:SELECT * FROM user WHERE name LIKE '%xxx%'
——开头的 AND 被自动去除,WHERE 自动补上。
注意边界情况
<where></where> 只处理紧邻的、作为条件起始的 AND/OR,不处理中间或结尾的多余运算符:
- 多个
<if></if>都为空 → 整个<where></where>块不生成,SQL 中无WHERE - 若某条
<if></if>内容是"OR type = 1",也会被正确剥离开头 OR - 不能混用
AND和OR在同一层级开头(语义易错),建议统一用AND+ 逻辑组合
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











