别再写一堆if了!Mybatis动态SQL的choose/when/otherwise标签,5分钟搞定多条件分支查询

张开发
2026/6/13 11:14:48 15 分钟阅读
别再写一堆if了!Mybatis动态SQL的choose/when/otherwise标签,5分钟搞定多条件分支查询
告别if嵌套噩梦MyBatis动态SQL的choose/when/otherwise实战指南在后台管理系统开发中我们经常遇到需要根据多种查询条件动态构建SQL的场景。比如用户可能选择按订单状态筛选或者按时间范围查询甚至需要根据不同用户类型访问不同的数据表。传统做法是堆砌大量if标签结果代码变得像意大利面条一样难以维护。今天我们就来聊聊如何用MyBatis的choose/when/otherwise标签优雅解决这个问题。1. 为什么需要choose/when/otherwise想象一下这样的场景电商后台需要实现一个订单查询功能支持以下筛选条件按订单状态待付款/待发货/已完成按订单类型普通/秒杀/团购按时间范围今日/本周/本月如果用传统if标签实现代码可能会长这样select idfindOrders resultTypeOrder SELECT * FROM orders where if teststatus ! null AND status #{status} /if if testtype ! null AND type #{type} /if if testtimeRange today AND create_time CURDATE() /if if testtimeRange week AND create_time DATE_SUB(CURDATE(), INTERVAL 7 DAY) /if !-- 更多if条件... -- /where /select这种写法存在几个明显问题条件优先级不明确所有条件都是AND关系无法实现要么A要么B的逻辑SQL冗余当多个条件互斥时生成的SQL可能包含不必要的判断可读性差随着条件增多代码会变得难以理解和维护2. choose/when/otherwise的基本用法choose/when/otherwise组合类似于Java中的switch-case结构让我们看个改造后的例子select idfindOrders resultTypeOrder SELECT * FROM orders where choose when testtimeRange today AND create_time CURDATE() /when when testtimeRange week AND create_time DATE_SUB(CURDATE(), INTERVAL 7 DAY) /when otherwise AND create_time DATE_SUB(CURDATE(), INTERVAL 30 DAY) /otherwise /choose if teststatus ! null AND status #{status} /if /where /select这个例子展示了choose标签的几个关键特点互斥执行只会执行第一个满足条件的when分支默认分支所有when都不满足时执行otherwise组合使用可以与其他动态SQL标签如if配合使用3. 高级应用场景3.1 多表查询动态选择在分库分表场景下我们经常需要根据某个字段值选择不同的表select idfindUserOrders resultTypeOrder SELECT * FROM choose when testuserType VIP vip_orders /when when testuserType ENTERPRISE enterprise_orders /when otherwise normal_orders /otherwise /choose WHERE user_id #{userId} /select3.2 复杂条件优先级处理考虑一个商品搜索场景我们希望优先按关键词搜索无关键词时按分类筛选既无关键词也无分类时展示推荐商品select idsearchProducts resultTypeProduct SELECT * FROM products where choose when testkeyword ! null AND (name LIKE CONCAT(%,#{keyword},%) OR description LIKE CONCAT(%,#{keyword},%)) /when when testcategoryId ! null AND category_id #{categoryId} /when otherwise AND is_recommended 1 /otherwise /choose if testminPrice ! null AND price #{minPrice} /if /where ORDER BY choose when testsortBy priceprice/when when testsortBy salessales_volume/when otherwisecreate_time DESC/otherwise /choose /select4. 常见问题与最佳实践4.1 性能优化建议避免过度使用只在真正需要互斥逻辑时使用choose简单条件仍用if条件顺序将最可能命中的条件放在前面组合索引确保where条件能够利用索引4.2 常见错误排查!-- 错误示例1when条件重叠 -- choose when teststatus 1.../when when teststatus 1.../when !-- 这个条件永远不会执行 -- /choose !-- 错误示例2缺少otherwise -- choose when testtype A.../when when testtype B.../when !-- 当type为C时整个choose块不会生成任何SQL -- /choose4.3 与其他标签的配合标签组合适用场景示例choose where条件查询wherechoose.../choose/wherechoose set条件更新setchoose.../choose/setchoose foreach批量操作foreachchoose.../choose/foreach5. 实际项目中的经验分享在最近的一个供应链管理系统中我们遇到了一个复杂的产品筛选需求。用户需要能够优先按产品编码精确匹配其次按产品名称模糊搜索最后按产品分类浏览最初我们使用了嵌套的if标签结果XML文件膨胀到300多行维护起来非常痛苦。重构为choose结构后代码量减少了40%逻辑也变得清晰明了select idfindProducts resultTypeProduct SELECT * FROM products where choose when testproductCode ! null AND code #{productCode} /when when testproductName ! null AND name LIKE CONCAT(%,#{productName},%) /when when testcategoryId ! null AND category_id #{categoryId} /when /choose AND is_active 1 /where /select另一个实用技巧是在otherwise中使用变量默认值select idgetUserList resultTypeUser SELECT * FROM users ORDER BY choose when testorderBy ! null${orderBy}/when otherwisecreate_time DESC/otherwise /choose LIMIT choose when testlimit ! null#{limit}/when otherwise20/otherwise /choose /select

更多文章