779 字
约 2 分钟
5
S08-B03 · 动态 SQL:`<if>` / `<where>` / `<foreach>`
适用读者:用
StringBuilder拼过 SQL 的人。
前置:S08-B02。
覆盖旧文:900(MyBatis 支持动态 SQL 吗,100 点)。
上一篇:S08-B02 · 参数与结果映射:#{}vs${}
下一篇:S08-B04 · MyBatis-Plus 基础。
1. 一句话结论
动态 SQL 的本质是"用标签生成 SQL 片段",解决手拼 SQL 的三个问题:多余的 and、多余的 where、以及逗号处理。
| 手拼 SQL 的问题 | 标签解法 |
|---|---|
where and name=? |
<where> 自动去掉开头的 and/or |
| 集合遍历的逗号 | <foreach> 的 separator |
| 分支判断 | <if test="..."> |
2. 五个核心标签
| 标签 | 作用 |
|---|---|
<if test="cond"> |
条件拼接 |
<choose>/<when>/<otherwise> |
多选一(类似 switch) |
<where> |
自动加 where 并去掉多余 and |
<set> |
更新语句自动去掉尾部逗号 |
<foreach> |
集合遍历(in 查询、批量插入) |
3. 标准写法
<select id="search" resultType="User">
select * from sys_user
<where>
<if test="name != null and name != ''">and user_name = #{name}</if>
<if test="minAge != null">and age >= #{minAge}</if>
</where>
order by id
</select>
<update id="updateSelective">
update sys_user
<set>
<if test="userName != null">user_name = #{userName},</if>
<if test="age != null">age = #{age},</if>
</set>
where id = #{id}
</update>
<select id="byIds" resultType="User">
select * from sys_user where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>
4. 三个容易踩的点
| 点 | 说明 |
|---|---|
test 里的 != '' |
空串判断要写(null 与 '' 是两种情况) |
<foreach> 的 collection 名 |
单参数 List 默认 list;@Param 后用参数名 |
<where> 不解决"没有条件" |
所有 <if> 都不成立时会变成 select * from t(全表)——要加兜底条件 |
最后一条最危险:动态条件全为空 → 全表扫描。
5. 与 MP 的 Wrapper 怎么选
| 场景 | 选 |
|---|---|
| 固定 SQL + 少量条件 | XML 动态 SQL(可读) |
| 条件由代码动态组合(多分支) | Wrapper(B05) |
| 复杂联表/子查询 | XML(Wrapper 表达力有限) |
判据:"这个 SQL 会被 3 个以上场景复用吗?" 会 → XML;不会且条件多 → Wrapper。
6. 五个误区
| 误区 | 真相 |
|---|---|
"<where> 保证不会全表" |
条件全空时就是全表 |
"<if test=\"name != null\"> 足够" |
空串仍会拼进去 |
"<foreach> 的 collection 随便写" |
名字不对会报错 |
"动态 SQL 只有 <if>" |
还有 choose/where/set/foreach/trim |
| "XML 一定比注解好" | 简单 SQL 用注解更直观 |
7. 自检
<where>解决了什么问题?不解决什么问题?<foreach>的collection什么时候是list、什么时候是参数名?- 为什么
test里要判空串? - XML 与 Wrapper 怎么选?
- 动态条件全为空会生成什么 SQL?
8. 下一篇
S08-B04 · MyBatis-Plus 基础:CRUD、注解、逻辑删除
动态 SQL 讲完,下一篇讲"少写 SQL"的路线:MP 的 CRUD、逻辑删除与乐观锁。
本篇属于系列《S08 · MyBatis 持久层》。旧文来源:A-900。
S08-B03 · 动态 SQL:`<if>` / `<where>` / `<foreach>`
https://www.clxhxhhr.top/posts/5284/ 评论
0 条
还没有评论,先写一条吧。