初识动态 SQL

26 阅读3分钟

动态 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> 标签的神奇之处:

它非常智能,被称为**“智能去噪”**标签。

  1. 如果里面的 <if> 全都不满足:它根本不会生成 WHERE 关键字(避免出现 select * from user where 这种语法错误)。
  2. 如果第一个 <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>包裹查询条件自动处理开头的 ANDOR,若无条件则不生成 WHERE
<set>包裹更新字段自动处理结尾多余的逗号
<foreach>循环遍历专门处理 IN (x, y, z) 这种列表查询或批量删除