【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;

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

所以我们希望 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 关键字,并且会自动去掉多余的 andor

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> 常用于遍历集合,完成批量删除、批量新增等操作。

相关推荐
ServBay1 小时前
7 个AI开发中真正用得上的 MCP Server,配合Claude Code食用效果更佳
后端·claude·mcp
妙码生花1 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十五):优化细节、网络请求封装
前端·后端·ai编程
用户6757049885022 小时前
Go 语言里判断字符串为空,90% 的人都写错了!
后端·go
Flittly2 小时前
【AgentScope Java新手村系列】(16)从RAG到多路检索
java·spring boot·spring
用户6757049885022 小时前
Go 进阶必修:90% 的人都没用对的“表驱动法”
后端·go
小兔崽子去哪了2 小时前
Java 生成二维码解决方案
java·后端
苍何2 小时前
懂事的 Agent 已经开始自己看屏幕干活了,效率起飞!
后端
掘金码甲哥3 小时前
1分钟买不了吃亏系列: nginx动态域名解析
后端
神奇小汤圆3 小时前
2026大厂Java岗面试记录:八股+场景+项目+AI,一文讲透快速上岸路径(含答案)
后端
神奇小汤圆3 小时前
我说MySQL每张表最好不超过2000万条数据,面试官让我回去等通知?
后端