【Spring Boot + MyBatis|第4篇】MyBatis 动态 SQL:if、where、foreach 使用详解

前言

前面我们已经学习了三层架构、参数接收和统一返回结果。接下来就要进入 MyBatis 中非常常用的一个知识点:动态 SQL。

在项目中,查询条件经常不是固定的。比如员工查询时,前端可能传姓名,也可能传性别,也可能两个都不传。如果我们给每一种情况都单独写一条 SQL,代码会非常混乱。

这时候就可以使用 MyBatis 动态 SQL。

一、为什么需要动态 SQL?

普通 SQL 是固定的:

sql 复制代码
select * from emp where name like '%张三%' and gender = 1;

但是实际查询时,name 和 gender 可能都不是必传参数。

所以我们希望 SQL 可以根据参数自动变化:

text 复制代码
传 name:按姓名查
传 gender:按性别查
都传:两个条件一起查
都不传:查询全部

这就是动态 SQL 的作用。

二、if 标签的使用

<if> 用来判断某个条件是否成立。

xml 复制代码
<select id="list" resultType="com.example.pojo.Emp">
    select *
    from emp
    where
        <if test="name != null and name != ''">
            name like concat('%', #{name}, '%')
        </if>
</select>

这里的意思是:如果 name 不为空,就拼接姓名查询条件。

但是这样写有一个问题:如果 name 为空,SQL 会变成:

sql 复制代码
select * from emp where

这条 SQL 是错误的,所以还需要配合 <where> 使用。

三、where 标签的使用

<where> 会自动生成 where 关键字,并且会自动去掉多余的 and 或 or。

xml 复制代码
<select id="list" resultType="com.example.pojo.Emp">
    select id, username, name, gender, phone
    from emp
    <where>
        <if test="name != null and name != ''">
            name like concat('%', #{name}, '%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
    </where>
    order by update_time desc
</select>

这样无论前端传几个条件,SQL 都能正常拼接。

四、Controller 层实现

java 复制代码
@GetMapping
public Result list(String name, Integer gender) {
    List<Emp> empList = empService.list(name, gender);
    return Result.success(empList);
}

Controller 负责接收前端传来的查询参数,然后调用 Service。

五、Service 层实现

java 复制代码
@Override
public List<Emp> list(String name, Integer gender) {
    return empMapper.list(name, gender);
}

Service 这里没有复杂业务,只是把参数继续传给 Mapper。

六、Mapper 层实现

java 复制代码
List<Emp> list(String name, Integer gender);

对应 XML:

xml 复制代码
<select id="list" resultType="com.example.pojo.Emp">
    select id, username, name, gender, phone
    from emp
    <where>
        <if test="name != null and name != ''">
            name like concat('%', #{name}, '%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
    </where>
</select>

这就是最常见的条件查询动态 SQL。

七、foreach 标签的使用

<foreach> 常用于批量删除。

比如前端传来多个 id:

text 复制代码
ids=1,2,3

Mapper XML 可以这样写:

xml 复制代码
<delete id="deleteByIds">
    delete from emp
    where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

最终 SQL 类似:

sql 复制代码
delete from emp where id in (1,2,3);

八、总结

动态 SQL 是 MyBatis 中非常重要的知识点,尤其是在条件查询和批量操作中经常使用。

<if> 用来判断条件是否拼接,<where> 用来自动处理 where 和多余的 and,<foreach> 常用于遍历集合,完成批量删除、批量新增等操作。

相关推荐
Lambert2811 分钟前
SAA 停摆的答案:前团队的 ARGI 我上手跑了一遍,缝了三针才跑通
后端·openai·ai编程
布吉岛的石头2 分钟前
Java 程序员第 49 阶段11:Java 接 BERT:用 ONNX Runtime 做句向量推理
java·人工智能·python·深度学习·bert·transformer
niucloud-admin11 分钟前
JAVA V6 多商户商城 开发文档——JAVA服务端
java·开发语言
SL_staff21 分钟前
设备越多系统越崩?根源在三层抽象失效
spring boot·物联网·github
alexlifexyz25 分钟前
写了个 Claude Code 插件:AI 写的 Java 违反阿里规约,就写不进文件
java
轻舟技术A26 分钟前
Pi 的 Rust 实现来了:rpi,不止一个终端 Agent
开发语言·后端·rust
站大爷IP35 分钟前
Python的字典遍历把我坑惨了,原来items和keys的区别这么大
后端
威哥爱编程38 分钟前
【AI全栈12-01】Spring Boot 为何是 AI 全栈后端优选
java·spring boot·后端
汉堡大王952739 分钟前
GPT-6 上线 48 小时,我扒开了 Intelligent UI 的运行机制:DIL、沙箱 Worker 和一个 React 式协调器
前端·javascript·后端