MyBatis 动态 SQL的使用场景与实现方法
前言:
在学习 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。”
只要理解这一点,你就已经入门了。
到此这篇关于MyBatis 动态 SQL的使用场景与实现方法的文章就介绍到这了,更多相关MyBatis 动态 SQL内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


最新评论