MyBatis动态SQL中不支持跨标签变量共享,是顺序匹配的if-else结构,需配合判空,XML无法处理复杂逻辑,应下沉至Java层。

MyBatis 中 标签的嵌套与作用域限制
MyBatis 的 不支持跨标签共享变量,每个 内部的表达式独立求值,且不能直接引用其他 中定义的临时变量。常见错误是试图在多个 间传递中间结果,比如先判断 status != null,再在后续 中用 status == 'ACTIVE' —— 这本身合法,但若中间加了 或拼接逻辑,就容易因 SQL 片段缺失导致语法错误。
实操建议:
-
test属性必须是 OGNL 表达式,status == 'ACTIVE'要写成status == 'ACTIVE'(单引号),不能用双引号(会被 XML 解析器提前截断) - 多个条件并列时,优先用
+ 多个,它会自动处理开头的AND/WHERE冗余问题 - 避免在
内写复杂 Java 逻辑;需要分支计算时,应前置到 DAO 方法或 Service 层完成
MyBatis 与 Java switch 的语义差异
更接近 if-else if-else,不是严格意义上的 switch:它按顺序匹配第一个为 true 的 ,其余全部跳过;没有“case 落空后执行 default”的隐式兜底机制, 必须显式写出,且只能有一个。
常见误用:
- 把
和并列写,因类型不一致导致两个都不命中 - 遗漏
,而业务上又存在未覆盖的输入值,最终生成空 SQL 片段,可能引发全表扫描 -
套在内时,若所有都不满足,整个可能为空,导致 SQL 语法错误
动态 SQL 中 与条件组合的边界情况
本身不带条件判断能力,常需和 配合使用。典型场景是「仅当集合非空时才拼入 IN 子句」,但容易忽略空集合、null 集合、元素含 null 值这三种状态。
正确写法示例:
AND id IN #{id}
注意点:
-
collection参数名必须与传入 Map 或对象属性名完全一致,区分大小写 - 若传入的是数组(如
int[]),MyBatis 默认识别为array,此时collection="array"才能遍历 -
open/close是纯字符串包裹,不参与逻辑判断;若ids为空,整个块被跳过,不会留下孤立的AND
XML 映射中无法实现的逻辑必须移出 SQL 层
XML 映射本质是模板引擎,不支持循环内嵌套条件、递归、闭包、异常捕获等编程语言特性。例如「对列表中每个用户,如果余额 > 100 则打标,否则查其上级再判断」这类逻辑,在 XML 里强行用 + 堆砌会导致可读性崩溃,且无法调试。
真正可行的做法:
- 把多层条件判断逻辑下沉到 Service 层,用 Java 完整控制流程,只将最终确定的参数(如
finalStatus、targetIds)传给 Mapper - 复杂查询优先考虑视图或数据库函数封装,而不是在 MyBatis XML 里模拟业务规则
- 需要运行时决定表名或字段名(如分表场景),用
${tableName}拼接,但必须严格校验输入,杜绝 SQL 注入
最常被忽略的一点:XML 里的任意逻辑都发生在 SQL 拼接阶段,而非执行阶段——这意味着所有 test 表达式在 JDBC PreparedStatement 构造前就已求值完毕,无法响应数据库返回的动态结果做二次判断。










