[MyBatis]动态SQL
简介
动态SQL,指的就是随着用户的输入或外部的条件的变化而变化的SQL语句。
比如说现在根据这个员工查询系统设计后端逻辑
前端会请求姓名 | 性别 | 入职开始日期 | 入职结束日期 但是不是每次请求都返回完完整整的四个参数
如果只根据姓名查询 或者只根据性别查询,则最普通的WHERE ... AND ...SQL语句查询不了这种情况
所以MyBatis提供了一中拼接and语句的SQL注入方式
该操作需要在定义在xml文件中的SQL语句进行修改
<if test=”…”>
1 | <if test="判断条件"> |
当test后的判断条件成立时才会拼接包围的SQL语句
但是这样做仍有一个弊端 比如需要执行 WHERE a = ? AND b = ?
当我a的判断条件不成立而b的判断条件成立时 只会进行b的拼接 就变成了``WHERE AND b = ?`
这显然是语法错误了
所以需要引入where这个标签
<where>
被where包围的所有if test标签会自动选择是否拼接AND
1 | <!--定义 Mapper 映射文件的约束和基本结构--> |
在这个xml文件中
where标签包围了三个if test标签 但是当name不生效时,后边的某一个生效时会自动去掉AND使得SQL语法合法
<foreach>
作用:遍历集合(List, Set, Array, Map),通常用于构建 IN 查询或批量插入。
场景:查询 ID 在某个列表里的所有用户 (WHERE id IN (1, 2, 3))。
关键属性:
collection: 参数类型 (list, array, 或 @Param 指定的名字)。item: 当前遍历到的元素变量名。open: 循环开始前的符号。close: 循环结束后的符号。separator: 每次循环之间的分隔符。
1 | <select id="findByIds" resultType="User"> |
<set>
作用:
- 自动插入
SET关键字。 - 智能去除内容末尾多余的逗号
,。 场景:更新操作。只更新传入了值的字段,没传值的字段保持原样。
XML
1 | <update id="updateUser"> |
注意:如果所有 if 都不成立,<set> 标签内为空,SQL 会报错。业务层需保证至少更新一个字段。
<choose>, <when>, <otherwise>
作用:类似于 Java 的 switch...case...default。只会执行其中一个分支。 场景:优先按 ID 查,没 ID 按名字查,都没传就查全部活跃用户。
1 | <select id="selectUserByChoice" resultType="User"> |
<trim>
<trim> 标签是所有动态 SQL 标签的底层父类(<where> 和 <set> 其实就是 <trim> 的预设模式)。
作用:自定义前缀、后缀以及要被覆盖(去掉)的字符。
场景:非常规的 SQL 拼接,或者你需要去掉后缀的 AND 而不是前缀。
1 | <trim prefix="SET" suffixOverrides=","> |
属性表
| 属性名 | 作用方向 | 含义 | 典型值 |
|---|---|---|---|
prefix |
加在开头 | 如果标签内有内容,就在最前面补上这个字符串 | WHERE, SET, ( |
suffix |
加在结尾 | 如果标签内有内容,就在最后面补上这个字符串 | ), END |
prefixOverrides |
删掉开头 | 如果标签内的内容以这些字符开头,就把它删掉 | AND, OR |
suffixOverrides |
删掉结尾 | 如果标签内的内容以这些字符结尾,就把它删掉 | , |
2. 逻辑执行流程
MyBatis 处理 <trim> 的顺序是这样的:
- 先生成内部 SQL:先把
<trim>标签里面的<if>跑一遍,拼出一个原始字符串。 - 判断空:如果拼出来的字符串是空的,
<trim>啥也不干,直接消失。 - 去多余(Overrides):如果字符串不为空,检查开头有没有命中
prefixOverrides,结尾有没有命中suffixOverrides,有则删掉。 - 补前缀后缀(Prefix/Suffix):删干净后,再在最前加
prefix,最后加suffix。
3. 实战演示
场景一:手写一个 <where> 标签
如果不使用 <where> 标签,用 <trim> 实现完全一样的功能:
XML
1 | <trim prefix="WHERE" prefixOverrides="AND |OR "> |
- 假设
state有值:内部生成AND state = 1。 prefixOverrides工作:发现开头是AND,删掉!变成state = 1。prefix工作:在前面加上WHERE。- 最终结果:
WHERE state = 1。 - 注意:
prefixOverrides如果有多个,用管道符|隔开,注意空格(如AND |OR)。


