mybatis的choose标签实现“多选一”逻辑:按顺序逐个判断when的test表达式,命中即执行其sql并终止后续判断;全部不满足时执行otherwise(若存在),本质是if-else if-else结构,非switch fall-through。
java switch 的分支动态选择">
MyBatis 的 `switch 逻辑,但它更接近 if-else if-else 结构——即**只执行第一个匹配成功的分支**,其余跳过,不是多路并行或 fall-through。正确理解这点是用好它的关键。
一、`` 的基本结构和执行逻辑
<choose></choose> 必须包含至少一个 <when></when>,可选一个 <otherwise></otherwise>。MyBatis 按顺序逐个判断 test 表达式,一旦某个 <when></when> 为 true,就执行其内部 SQL 片段,且**立即终止后续所有判断**;若全部 <when></when> 都不满足,才执行 <otherwise></otherwise>(如果存在)。
- 不支持“多个条件同时生效”,也不支持类似 switch 的
break缺失导致的穿透 -
test表达式写法同<if></if>:支持 OGNL,如status == 'PENDING'、type != null and type != '' - 所有标签都必须嵌套在
<where></where>、<set></set>或普通 SQL 节点内,不能单独使用
二、典型场景:动态 WHERE 条件筛选
比如根据用户传入的查询类型(全部/待审核/已通过)拼接不同条件:
<select id="selectOrders" resulttype="Order">
SELECT * FROM orders
<where><choose><when test="queryType == 'ALL'">
status IN ('PENDING', 'APPROVED', 'REJECTED')
</when><when test="queryType == 'PENDING'">
status = 'PENDING'
</when><when test="queryType == 'APPROVED'">
status = 'APPROVED'
</when><otherwise>
status = 'PENDING' <!-- 默认行为 -->
</otherwise></choose></where></select>
注意:<where></where> 会自动处理 AND 前缀和空格,避免因分支为空导致语法错误。
三、配合 `` 实现动态更新字段
更新时只修改非空字段,但需按业务规则决定哪些字段允许被设为 NULL 或忽略:
<update id="updateOrder">
UPDATE orders
<set><choose><when test="order.status != null and order.status != 'INIT'">
status = #{order.status},
</when><when test="order.amount != null and order.amount > 0">
amount = #{order.amount},
</when><otherwise>
updated_at = NOW(),
</otherwise></choose>
update_time = NOW()
</set>
WHERE id = #{order.id}
</update>
这里每个 <when></when> 内部可以写多条 SQL(用逗号分隔),<set></set> 会自动剔除末尾多余逗号。
四、常见误区与注意事项
-
别把
<choose></choose>当成 SQL 的 CASE WHEN:它不生成数据库端的CASE表达式,只是 XML 层的条件拼接 -
<otherwise></otherwise>不是必需的,但建议显式写出,避免逻辑遗漏 - OEL 表达式中字符串比较要用单引号,如
type == 'USER',双引号在某些 MyBatis 版本可能解析异常 - 嵌套使用时注意缩进和可读性,复杂逻辑建议拆到 Service 层预处理,保持 XML 简洁
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











