"小崔,动态SQL不是10个标签背一遍,是4套积木组合。记住场景,比记住标签重要。"——白歌
本章定位
一句话:本章解决"如何根据运行时条件动态组装SQL、避免拼接字符串带来的SQL注入和代码混乱"的问题。
飞翔科技的后台管理系统上线后,黄俪设计的筛选面板有12个可选条件,小崔在DAO层用Java拼接SQL,不仅代码臃肿,还差点引入SQL注入漏洞。白歌直接否决:全部改用MyBatis动态SQL标签。这一章,小崔把10个标签当成4套"积木"来学。
学习路线图
学习顺序说明:
- 先学条件判断(if / choose_when_otherwise)→ 掌握"要不要加这段SQL"的控制权
- 再学智能包裹(where / set / trim)→ 掌握"加了之后前缀后缀怎么处理"的自动化
- 再学批量迭代(foreach / bind)→ 掌握"IN查询、批量插入、动态变量绑定"
- 最后看高级扩展(script / databaseId / 脚本语言)→ 掌握多数据库适配和OGNL/MVEL等脚本扩展
文件关系说明
| 文件 | 一句话角色 |
|---|---|
if.md | 条件判断基石:单条件开关,test属性写OGNL表达式,决定是否包含某段SQL |
choose_when_otherwise.md | 多选一组合:Java中switch的XML等价物,互斥条件场景(如:按状态/按时间/默认) |
where.md | 智能WHERE包裹:自动处理首条条件前的AND/OR,避免WHERE AND语法错误 |
trim.md | 通用前缀后缀裁剪:where和set的"超集",可自定义prefix/suffix/prefixOverrides/suffixOverrides |
set.md | 智能SET包裹:动态更新时自动处理字段间的逗号,避免SET col1=?, ,col2=?错误 |
foreach.md | 批量迭代核心:IN查询、批量插入、批量更新的循环构造器 |
bind.md | 变量预绑定:在SQL执行前创建OGNL变量,常用于模糊查询拼接% |
script.md | 脚本包裹器:在注解或XML中包裹动态SQL脚本,支持更复杂的逻辑 |
_databaseId与动态SQL多数据库支持.md | 多数据库适配:根据databaseId切换不同方言的动态SQL分支 |
动态SQL中插入脚本语言.md | 语言扩展:在动态SQL中嵌入OGNL、MVEL等脚本引擎的进阶用法 |
知识图谱
核心概念关系:
if和choose是"决策层",决定哪些SQL片段进入最终语句where / set / trim是"格式化层",解决动态拼接带来的语法瑕疵(多余的AND、逗号)foreach和bind是"数据层",处理集合遍历和变量预处理- 常见组合场景:
- if + where:多条件查询的标准组合,where自动吞掉第一个if前的AND
- foreach + bind:批量IN查询前用bind拼接
%keyword%,再用foreach遍历ID列表 - choose + when + otherwise:排序规则互斥选择(按时间/按热度/默认按ID)
- trim + set:复杂更新场景,set是trim的特例,trim可处理更自定义的前缀后缀
与下一章的衔接
本章学完后,小崔能写灵活的动态SQL,但遇到"订单里嵌套用户信息"、"部门下挂多个员工"这种对象关系映射时,单表的resultType和简单resultMap已经不够用了。
下一章《结果映射与关联查询》将解决:如何用 association(一对一)、collection(一对多)、discriminator(鉴别器)处理复杂对象图,以及延迟加载和N+1问题的规避策略。
"动态SQL解决了'SQL怎么写'的问题,结果映射解决了'查回来的数据怎么变成对象'的问题。两个都通了,才算真正会写MyBatis。"——白歌