🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)
🎬精选专栏:数据结构与算法,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。”
只要理解这一点,你就已经入门了。
今天的学习就暂时告一段落啦,如果文章对您有用的话,还请留下一个免费的小心心和关注哦!
祝您工作顺利,生活愉快。我们下期再见!