🌈个人主页 :一条泥憨鱼 (欢迎各位大佬莅临)
🎬精选专栏:数据结构与算法 ,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,代码会非常麻烦。
例如:
java
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 可以优雅解决这些问题。
三、准备工作
假设有一张用户表:
sql
CREATE TABLE user(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
age INT,
gender VARCHAR(10)
);
对应实体类:
java
public class User {
private Integer id;
private String username;
private Integer age;
private String gender;
// getter/setter
}
Mapper接口:
java
public interface UserMapper {
List<User> select(User user);
}
四、<if> 标签
这是最常用的动态 SQL 标签。
作用:
条件成立时才拼接 SQL
1、基本使用
sql
<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:
java
User user = new User();
user.setUsername("Tom");
生成 SQL:
java
SELECT * FROM user
WHERE 1=1
AND username = 'Tom'
情况2:
java
User user = new User();
user.setAge(20);
生成 SQL:
java
SELECT * FROM user
WHERE 1=1
AND age = 20
五、<where> 标签
很多初学者都会写:
WHERE 1=1
虽然能用,但不优雅。
MyBatis 提供了:
<where>
它能自动:
-
添加 WHERE
-
去掉多余的 AND
1、改造代码
sql
<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
如果有条件:
sql
SELECT * FROM user
WHERE username = 'Tom'
是不是优雅很多?
六、<set> 标签
用于动态更新 SQL
1、需求
用户修改信息时:
-
只修改传入的字段
-
空字段不更新
2、代码实现
sql
<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
sql
UPDATE user
SET username = 'Tom',
age = 20
WHERE id = 1
七、<foreach> 标签
这是开发中非常重要的标签。
作用:循环遍历集合
最经典的场景:批量查询
1、需求
查询多个 ID:
sql
SELECT * FROM user WHERE id IN (1,2,3)
2、Mapper接口
java
List<User> selectByIds(List<Integer> ids);
3、XML写法
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
sql
SELECT * FROM user
WHERE id IN (1,2,3)
八、<choose> 标签
类似 Java 中的:
switch-case
作用:多选一
示例
sql
<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> 标签
这是一个高级标签。
作用:自定义字符串拼接规则
示例
sql
<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接口
java
List<User> selectCondition(User user);
XML
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>
测试代码
java
User user = new User();
user.setUsername("o");
user.setGender("男");
List<User> users = mapper.selectCondition(user);
users.forEach(System.out::println);
生成 SQL
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。"只要理解这一点,你就已经入门了。
今天的学习就暂时告一段落啦,如果文章对您有用的话,还请留下一个免费的小心心和关注哦!
祝您工作顺利,生活愉快。我们下期再见!