动态 SQL 是 MyBatis 最强大的特性之一。
简单来说,它的核心思想是:SQL 语句不是写死的,而是根据你传进来的参数,像搭积木一样“自动组装”出来的。
我们用一个最常见的**“多条件搜索”**场景来把这个问题讲透。
1. 为什么要用动态 SQL?(痛点)
想象一下,你的外卖软件有一个“筛选”功能。用户可以只搜“川菜”,也可以搜“川菜”+“价格低于20元”,还可以搜“川菜”+“免配送费”。
如果没有动态 SQL,你可能要在 Java 代码里写一堆丑陋的 if-else 来拼接字符串:
Java
// ❌ 以前的笨办法(容易出错,容易被注入)
String sql = "select * from food where 1=1";
if (name != null) {
sql += " and name = " + name;
}
if (price != null) {
sql += " and price < " + price;
}
有了动态 SQL,你只需要在 XML 里写好逻辑,MyBatis 会自动帮你处理所有的空格、AND、逗号问题。
2. 核心标签一:<if> 和 <where>(最常用)
这是你 90% 的时间都会用到的组合。
场景:
用户可能输入了名字,也可能没输;可能选了性别,也可能没选。我们要根据输入情况自动生成 SQL。
代码示例:
XML
<select id="list" resultType="com.itmob.pojo.User">
select * from user
<where>
<if test="name != null and name != ''">
and name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
</where>
</select>
<where> 标签的神奇之处:
它非常智能,被称为**“智能去噪”**标签。
- 如果里面的
<if>全都不满足:它根本不会生成WHERE关键字(避免出现select * from user where这种语法错误)。 - 如果第一个
<if>满足了:它会自动把最前面的AND去掉(避免出现select * from user where AND name = ...这种错误)。
3. 核心标签二:<set>(用于修改)
场景:
你要修改用户信息。用户只改了头像,没改名字。你只想更新 avatar 字段,不想把 name 字段覆盖成空。
代码示例:
XML
<update id="updateUser">
update user
<set>
<if test="name != null"> name = #{name}, </if>
<if test="age != null"> age = #{age}, </if>
<if test="updateTime != null"> update_time = #{updateTime}, </if>
</set>
where id = #{id}
</update>
<set> 标签的神奇之处:
它会自动去掉最后多余的一个逗号。
- 如果三个字段都改了,SQL 结尾是
..., update_time = xxx(没逗号)。 - 如果没有
<set>标签,你很难处理最后一个字段后面的逗号问题。
4. 核心标签三:<foreach>(用于批量操作)
场景:
你要在这个后台系统里做一个“批量删除”功能。用户勾选了 ID 为 1, 3, 5 的三个用户,点删除。
你需要生成的 SQL 是:delete from user where id in (1, 3, 5)。
代码示例:
XML
<delete id="deleteBatch">
delete from user where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
open="(":开始时加个左括号。separator=",":每遍历一个元素,中间加个逗号。close=")":结束时加个右括号。- 结果:自动拼成
(1, 3, 5)。
总结
动态 SQL 就是把逻辑判断从 Java 代码移到了 SQL 映射文件中。
| 标签 | 作用 | 智能点 |
|---|---|---|
<if> | 条件判断 | 类似于 Java 里的 if |
<where> | 包裹查询条件 | 自动处理开头的 AND 或 OR,若无条件则不生成 WHERE |
<set> | 包裹更新字段 | 自动处理结尾多余的逗号 |
<foreach> | 循环遍历 | 专门处理 IN (x, y, z) 这种列表查询或批量删除 |