news 2026/5/28 2:05:29

详解MyBatis 动态 SQL

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
详解MyBatis 动态 SQL

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

🎬精选专栏:数据结构与算法,JavaSE ,苍穹外卖日记,AI学习

前言:

在学习 JavaWeb 或企业级开发时,很多同学都会遇到一个问题:

“查询条件不固定,SQL 语句到底该怎么写?”

比如:

  • 用户可能输入用户名,也可能不输入

  • 商品查询可能按价格、分类、库存组合搜索

  • 更新用户信息时,有些字段可能为空

如果全靠字符串拼接 SQL,不但代码难看,而且容易出错。

于是,MyBatis 提供了一个非常强大的功能:

动态 SQL

它可以让 SQL “像程序一样”动态变化。

这篇文章会带你从零开始,彻底搞懂 MyBatis 动态 SQL。


一、什么是动态 SQL?

先看一个普通 SQL:

SELECT * FROM user WHERE username = 'Tom';

但现实中,用户名可能为空。

那么 SQL 就需要动态变化:

SELECT * FROM user;

或者:

SELECT * FROM user WHERE username = 'Tom';

这就是:SQL 根据条件动态变化

MyBatis 提供了很多标签帮助我们实现这种功能。

最常用的有:

标签作用
<if>条件判断
<where>自动处理 WHERE
<set>自动处理 UPDATE
<foreach>循环遍历
<choose>类似 switch
<trim>自定义拼接规则

二、为什么需要动态 SQL?

如果不用动态 SQL,代码会非常麻烦。

例如:

String sql = "select * from user where 1=1"; if(username != null){ sql += " and username = #{username}"; } if(age != null){ sql += " and age = #{age}"; }

问题很多:

  • 可读性差

  • SQL 拼接容易出错

  • 不方便维护

  • 容易产生 SQL 注入风险

MyBatis 动态 SQL 可以优雅解决这些问题。


三、准备工作

假设有一张用户表:

CREATE TABLE user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), age INT, gender VARCHAR(10) );

对应实体类:

public class User { private Integer id; private String username; private Integer age; private String gender; // getter/setter }

Mapper接口:

public interface UserMapper { List<User> select(User user); }

四、<if>标签

这是最常用的动态 SQL 标签。

作用:

条件成立时才拼接 SQL


1、基本使用

<select id="select" resultType="User"> SELECT * FROM user WHERE 1=1 <if test="username != null"> AND username = #{username} </if> <if test="age != null"> AND age = #{age} </if> </select>

2、执行效果

情况1:

User user = new User(); user.setUsername("Tom");

生成 SQL:

SELECT * FROM user WHERE 1=1 AND username = 'Tom'

情况2:

User user = new User(); user.setAge(20);

生成 SQL:

SELECT * FROM user WHERE 1=1 AND age = 20

五、<where>标签

很多初学者都会写:

WHERE 1=1

虽然能用,但不优雅。

MyBatis 提供了:

<where>

它能自动:

  • 添加 WHERE

  • 去掉多余的 AND


1、改造代码

<select id="select" resultType="User"> SELECT * FROM user <where> <if test="username != null"> AND username = #{username} </if> <if test="age != null"> AND age = #{age} </if> </where> </select>

2、效果

如果没有任何条件:

SELECT * FROM user

如果有条件:

SELECT * FROM user WHERE username = 'Tom'

是不是优雅很多?


六、<set>标签

用于动态更新 SQL


1、需求

用户修改信息时:

  • 只修改传入的字段

  • 空字段不更新


2、代码实现

<update id="updateUser"> UPDATE user <set> <if test="username != null"> username = #{username}, </if> <if test="age != null"> age = #{age}, </if> <if test="gender != null"> gender = #{gender}, </if> </set> WHERE id = #{id} </update>

3、作用

<set>会自动:

  • 添加 SET

  • 去掉最后一个逗号


4、生成 SQL

UPDATE user SET username = 'Tom', age = 20 WHERE id = 1

七、<foreach>标签

这是开发中非常重要的标签。

作用:循环遍历集合

最经典的场景:批量查询


1、需求

查询多个 ID:

SELECT * FROM user WHERE id IN (1,2,3)

2、Mapper接口

List<User> selectByIds(List<Integer> ids);

3、XML写法

<select id="selectByIds" resultType="User"> SELECT * FROM user <where> <foreach collection="list" item="id" open="id IN (" separator="," close=")"> #{id} </foreach> </where> </select>

4、参数解释

属性作用
collection集合名称
item每次遍历元素
open开始字符串
separator分隔符
close结束字符串

5、生成 SQL

SELECT * FROM user WHERE id IN (1,2,3)

八、<choose>标签

类似 Java 中的:

switch-case

作用:多选一


示例

<select id="select" resultType="User"> SELECT * FROM user <where> <choose> <when test="username != null"> username = #{username} </when> <when test="age != null"> age = #{age} </when> <otherwise> gender = '男' </otherwise> </choose> </where> </select>

逻辑

  • username 有值 → 按 username 查询

  • 否则 age 有值 → 按 age 查询

  • 都没有 → 默认查询 gender='男'


九、<trim>标签

这是一个高级标签。

作用:自定义字符串拼接规则


示例

<trim prefix="WHERE" prefixOverrides="AND |OR "> <if test="username != null"> AND username = #{username} </if> <if test="age != null"> AND age = #{age} </if> </trim>

含义

属性作用
prefix添加前缀
prefixOverrides删除前缀
suffix添加后缀
suffixOverrides删除后缀

实际上:

<where>

底层本质上就是:

<trim>

的封装。


十、动态 SQL 执行流程

很多同学会问:

MyBatis 是怎么让 SQL 动态变化的?

流程如下:

XML动态SQL ↓ MyBatis解析标签 ↓ 拼接最终SQL ↓ 预编译SQL ↓ 执行数据库操作

所以:

动态 SQL 本质上是 SQL 的动态拼接

但它比手写字符串安全得多。


十一、动态 SQL 的开发技巧


1、优先使用<where>

不要再:

WHERE 1=1

了。


2、更新操作使用<set>

避免:

age = 20,

最后多逗号报错。


3、批量操作一定学会<foreach>

企业开发中极其常见。

例如:

  • 批量删除

  • 批量查询

  • 批量插入


4、避免 SQL 过于复杂

动态 SQL 很强大,但不要把所有业务逻辑都写进 SQL

否则后期维护会非常痛苦。


十二、完整案例:多条件查询


Mapper接口

List<User> selectCondition(User user);

XML

<select id="selectCondition" resultType="User"> SELECT * FROM user <where> <if test="username != null and username != ''"> AND username LIKE CONCAT('%',#{username},'%') </if> <if test="age != null"> AND age = #{age} </if> <if test="gender != null"> AND gender = #{gender} </if> </where> </select>

测试代码

User user = new User(); user.setUsername("o"); user.setGender("男"); List<User> users = mapper.selectCondition(user); users.forEach(System.out::println);

生成 SQL

SELECT * FROM user WHERE username LIKE '%o%' AND gender = '男'

十三、动态 SQL 常见面试题


1、动态 SQL 有哪些标签?

常见:

  • <if>

  • <where>

  • <set>

  • <foreach>

  • <choose>

  • <trim>


2、<where>有什么作用?

自动:

  • 添加 WHERE

  • 删除多余 AND/OR


3、<set>有什么作用?

自动:

  • 添加 SET

  • 删除最后逗号


4、#{}${}区别?

#{}

预编译:

WHERE id = ?

安全,推荐使用。


${}

字符串拼接:

ORDER BY age

存在 SQL 注入风险。


十四、总结

动态 SQL 是 MyBatis 中最核心的能力之一。

掌握后你就能真正写出:

  • 灵活的查询

  • 动态更新

  • 批量操作

  • 企业级 SQL


重点回顾

标签核心作用
<if>条件判断
<where>自动处理 WHERE
<set>动态更新
<foreach>循环集合
<choose>多选一
<trim>自定义拼接

很多初学者觉得:

“动态 SQL 好复杂。”

“根据条件,动态拼接 SQL。”

只要理解这一点,你就已经入门了。

今天的学习就暂时告一段落啦,如果文章对您有用的话,还请留下一个免费的小心心和关注哦!

祝您工作顺利,生活愉快。我们下期再见!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 2:02:11

2026网文圈变天?实测国内12款AI写小说平台硬核盘点(建议收藏)

作为一个白天敲代码、晚上码网文的兼职“触手怪”&#xff0c;2026年开年以来&#xff0c;我最直观的感受就是&#xff1a;网文圈的生产力工具彻底迭代了。如果你的记忆还停留在2023、2024年那种“我说一句话&#xff0c;AI吐一段充满翻译腔的废话”的阶段&#xff0c;那只能说…

作者头像 李华
网站建设 2026/5/28 1:59:43

双节锂电池充电管理IC选型,输入电压范围覆盖4.2V至30V

双节锂电池充电IC — 平芯微充电管理芯片产品系列 技术概述 两节串联锂电池&#xff08;2S&#xff09;因其标称电压 7.4V、满电电压 8.4V、工作电压范围 6V\~8.4V 的特性&#xff0c;广泛应用 于蓝牙音箱、便携式电动工具、无人机、矿灯、手持终端、移动电源等需要较高工作电压…

作者头像 李华