在实际开发中,SQL 语句往往不是固定的,而是需要根据传入参数动态拼接。例如:用户可能只填写部分搜索条件,或管理员需要按不同状态筛选数据。MyBatis 提供了一套强大的 动态 SQL 机制,通过 XML 标签实现条件判断、循环、拼接等逻辑,避免手写繁琐的字符串拼接。
本文将系统介绍 MyBatis 中最常用的动态 SQL 标签及其使用场景。
一、<if>:条件判断
用于根据条件决定是否包含某段 SQL。
<select id="findUsers" resultType="User"> SELECT * FROM user WHERE 1=1 <if test="username != null and username != ''"> AND username LIKE CONCAT('%', #{username}, '%') </if> <if test="status != null"> AND status = #{status} </if> </select>
✅ 技巧:
使用
WHERE 1=1可避免因第一个条件不满足导致WHERE后无内容的语法错误。但更推荐使用<where>标签(见下文)。
二、<where>:智能处理 WHERE 子句
自动处理 AND/OR 的前缀问题,并在无条件时省略整个 WHERE 子句。
<select id="findUsers" resultType="User"> SELECT * FROM user <where> <if test="username != null"> username LIKE CONCAT('%', #{username}, '%') </if> <if test="status != null"> AND status = #{status} </if> </where> </select>
✅ 优势:
- 自动去除开头多余的
AND或OR;- 若所有
<if>都不满足,则不生成WHERE,SQL 仍合法。
三、<choose>、<when>、<otherwise>:多条件分支
类似 Java 中的 switch...case,只执行第一个满足条件的分支。
<select id="findUserByCondition" resultType="User"> SELECT * FROM user <where> <choose> <when test="id != null"> id = #{id} </when> <when test="username != null"> username = #{username} </when> <otherwise> status = 'ACTIVE' </otherwise> </choose> </where> </select>
📌 适用场景:互斥条件,如“按 ID 查”或“按用户名查”,优先级明确。
四、<foreach>:循环遍历集合
常用于 IN 查询、批量插入等场景。
1. IN 查询
<select id="selectByIds" resultType="User"> SELECT * FROM user WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </select>
collection:传入的集合(List、Array 或 Map 中的 key);item:当前元素变量名;open/close:包裹整个集合的符号;separator:元素之间的分隔符。
2. 批量插入
<insert id="batchInsert"> INSERT INTO user (username, email) VALUES <foreach collection="users" item="user" separator=","> (#{user.username}, #{user.email}) </foreach> </insert>
⚠️ 注意:
若传入的是 List,
collection="list";若为数组,collection="array";若为自定义参数(如@Param("users")),则用对应名称。
五、<set>:智能更新字段
用于 UPDATE 语句,自动处理逗号分隔,并忽略未设置的字段。
<update id="updateUser"> UPDATE user <set> <if test="username != null">username = #{username},</if> <if test="email != null">email = #{email},</if> <if test="status != null">status = #{status}</if> </set> WHERE id = #{id} </update>
✅ 效果:
若只传了
username和status,生成的 SQL 为:
UPDATE user SET username = ?, status = ? WHERE id = ?
自动去除末尾逗号,避免语法错误。
六、<trim>:通用前缀/后缀处理
<where> 和 <set> 实际上是 <trim> 的特例。你也可以自定义。
<!-- 等效于 <where> --> <trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim> <!-- 等效于 <set> --> <trim prefix="SET" suffixOverrides=","> ... </trim>
prefix:添加前缀;prefixOverrides:去除开头指定字符串;suffix/suffixOverrides:同理处理结尾。
七、<bind>:创建变量
可用于模糊查询中预处理参数,避免数据库方言差异。
<select id="findUserByName" resultType="User"> <bind name="pattern" value="'%' + username + '%'" /> SELECT * FROM user WHERE username LIKE #{pattern} </select>
✅ 优势:兼容 MySQL、Oracle、PostgreSQL 等不同数据库的
LIKE语法。
总结:动态 SQL 标签速查表
| 标签 | 用途 | 典型场景 |
<if> |
条件包含 | 可选查询条件 |
<where> |
智能 WHERE | 多条件组合查询 |
<choose> |
多选一分支 | 互斥条件 |
<foreach> |
循环 | IN 查询、批量操作 |
<set> |
智能 SET | 动态更新字段 |
<trim> |
自定义修剪 | 高级控制 |
<bind> |
创建变量 | 模糊查询、表达式复用 |
掌握这些动态 SQL 标签,你就能轻松应对各种复杂查询和更新场景,写出既安全又高效的 MyBatis 映射代码。