XML映射中的条件判断和逻辑如何实现?

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 层完成

MyBati

s 与 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 完整控制流程,只将最终确定的参数(如 finalStatustargetIds)传给 Mapper
  • 复杂查询优先考虑视图或数据库函数封装,而不是在 MyBatis XML 里模拟业务规则
  • 需要运行时决定表名或字段名(如分表场景),用 ${tableName} 拼接,但必须严格校验输入,杜绝 SQL 注入

最常被忽略的一点:XML 里的任意逻辑都发生在 SQL 拼接阶段,而非执行阶段——这意味着所有 test 表达式在 JDBC PreparedStatement 构造前就已求值完毕,无法响应数据库返回的动态结果做二次判断。