当前位置: 首页 > news >正文

MyBatis-Plus 中 and() 与 or() 的嵌套组合:构建复杂查询条件的实战解析

1. 初识MyBatis-Plus的条件构造器

第一次接触MyBatis-Plus的QueryWrapper时,我就被它的简洁语法惊艳到了。相比传统的MyBatis需要手写XML SQL语句,QueryWrapper通过链式调用就能构建复杂的查询条件。特别是and()和or()这两个方法,简直就是处理多条件查询的神器。

记得我刚接手一个后台管理系统时,需要实现用户的多条件筛选功能。比如要查询"年龄大于25岁且(姓名包含张或手机号以138开头)"的用户。如果用传统方式,这个SQL写起来会很复杂,而QueryWrapper只需要几行代码就能搞定:

QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age", 25) .and(qw -> qw.like("name", "张").or().like("phone", "138%"));

这段代码生成的SQL正是我们想要的:WHERE age > 25 AND (name LIKE '%张%' OR phone LIKE '138%')。这种Lambda表达式的写法不仅直观,还能自动处理括号的嵌套关系,大大减少了出错的可能性。

2. 理解and()和or()的基本用法

2.1 and()方法的本质

and()在QueryWrapper中表示逻辑"与"的关系。它有两种使用方式:

  1. 隐式调用:直接链式调用条件方法时,默认就是and关系
wrapper.eq("status", 1).ge("create_time", "2023-01-01"); // 等同于 WHERE status = 1 AND create_time >= '2023-01-01'
  1. 显式调用:通过and()方法包裹条件组
wrapper.eq("dept_id", 10) .and(qw -> qw.gt("salary", 5000).lt("salary", 10000)); // 等同于 WHERE dept_id = 10 AND (salary > 5000 AND salary < 10000)

实际项目中我发现,显式使用and()的主要场景是需要对一组条件整体进行AND运算时,特别是这组条件本身又包含OR关系的时候。

2.2 or()方法的妙用

or()表示逻辑"或"的关系,同样有两种使用方式:

  1. 简单条件OR连接
wrapper.eq("type", 1).or().eq("type", 2); // WHERE type = 1 OR type = 2
  1. 复杂条件OR组合
wrapper.eq("status", 1) .or(qw -> qw.eq("status", 2).ge("create_time", "2023-01-01")); // WHERE status = 1 OR (status = 2 AND create_time >= '2023-01-01')

在商品筛选功能中,我经常用or()来实现"满足A条件或者同时满足B和C条件"这类需求。比如查询"特价商品或(新品且库存充足)"的商品列表。

3. 嵌套组合的实战技巧

3.1 实现A AND (B OR C)结构

这是最常见的嵌套需求之一。假设我们要查询"部门ID为10且(职称为高级或者入职满3年)"的员工:

QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.eq("dept_id", 10) .and(qw -> qw.eq("title", "高级").or().ge("hire_years", 3));

这里的关键点是:

  1. 先用eq()设置dept_id条件
  2. 然后用and()包裹一个Lambda表达式
  3. 在Lambda内部使用or()连接两个条件

生成的SQL是:WHERE dept_id = 10 AND (title = '高级' OR hire_years >= 3)

3.2 实现A OR (B AND C)结构

另一种常见场景是"满足A条件或者同时满足B和C条件"。比如查询"状态为待审核,或者(创建时间在今天且优先级高)"的工单:

QueryWrapper<Order> wrapper = new QueryWrapper<>(); wrapper.eq("status", "待审核") .or(qw -> qw.ge("create_time", LocalDate.now()) .eq("priority", "高"));

这个例子中:

  1. 先用eq()设置status条件
  2. 然后用or()包裹Lambda表达式
  3. Lambda内部用ge()和eq()实现AND关系

生成的SQL是:WHERE status = '待审核' OR (create_time >= '2023-07-20' AND priority = '高')

3.3 多层嵌套的复杂场景

在一些特别复杂的查询中,可能需要三层甚至更多层的嵌套。比如查询"(部门为技术部且(职称为高级或工作满5年))或(部门为市场部且KPI达标)"的员工:

QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.and(qw1 -> qw1.eq("dept", "技术部") .and(qw2 -> qw2.eq("title", "高级") .or().ge("work_years", 5))) .or(qw -> qw.eq("dept", "市场部") .eq("kpi", "达标"));

这种多层嵌套的写法虽然复杂,但只要遵循"每个括号对应一个Lambda表达式"的原则,就能清晰地构建出想要的查询结构。

4. 常见问题与解决方案

4.1 括号位置错误的排查

刚开始使用嵌套查询时,我最常遇到的问题就是生成的SQL括号位置不对。比如想要A AND (B OR C),结果生成了(A AND B) OR C。这种情况通常是因为Lambda表达式的作用范围没搞清楚。

错误示例:

// 错误的写法:生成的SQL是 (dept_id = 10 AND title = '高级') OR hire_years >= 3 wrapper.eq("dept_id", 10) .eq("title", "高级") .or().ge("hire_years", 3);

正确写法:

// 正确的写法:生成的SQL是 dept_id = 10 AND (title = '高级' OR hire_years >= 3) wrapper.eq("dept_id", 10) .and(qw -> qw.eq("title", "高级").or().ge("hire_years", 3));

4.2 条件优先级混淆

另一个常见问题是逻辑运算符的优先级混淆。SQL中AND的优先级高于OR,所以A AND B OR C实际上等同于(A AND B) OR C。如果不加括号明确优先级,可能会得到不符合预期的查询结果。

解决方案:

  1. 明确使用括号来指定优先级
  2. 复杂的条件组合尽量拆分成多个Lambda表达式
  3. 使用QueryWrapper的nested()方法进行更精细的控制

4.3 动态条件构建技巧

在实际项目中,查询条件往往是动态的。比如用户可能只填写了部分筛选条件。这时候就需要动态构建QueryWrapper:

QueryWrapper<User> wrapper = new QueryWrapper<>(); if (StringUtils.isNotBlank(name)) { wrapper.like("name", name); } if (minAge != null) { wrapper.ge("age", minAge); } if (maxAge != null) { wrapper.le("age", maxAge); } if (hobbies != null && !hobbies.isEmpty()) { wrapper.and(qw -> { for (String hobby : hobbies) { qw.or().like("hobbies", hobby); } }); }

这种写法可以灵活应对各种条件组合,而且生成的SQL都是正确嵌套的。

5. 性能优化建议

5.1 避免过度嵌套

虽然嵌套查询很强大,但过度嵌套会影响SQL性能。特别是在处理大数据表时,建议:

  1. 嵌套层级不要超过3层
  2. 复杂的查询考虑拆分成多个简单查询
  3. 必要时使用JOIN代替嵌套条件

5.2 索引友好型写法

为了让查询能够利用索引,在构建条件时要注意:

  1. 等值条件(=)放在OR条件的前面
  2. 范围查询(>,<)尽量放在最后
  3. 避免在索引列上使用NOT、!=等否定操作

例如:

// 好的写法:能够利用dept_id和status的索引 wrapper.eq("dept_id", 10) .and(qw -> qw.eq("status", 1).or().eq("status", 2)); // 不好的写法:无法利用索引 wrapper.eq("dept_id", 10) .and(qw -> qw.ne("status", 0).or().eq("status", 3));

5.3 条件顺序优化

条件的顺序也会影响查询性能。一般原则是:

  1. 选择性高的条件放在前面
  2. 能够过滤掉大量数据的条件优先执行
  3. 计算成本高的条件尽量靠后

比如查询活跃用户:

// 优化后的写法:先过滤掉非活跃用户 wrapper.eq("is_active", 1) .and(qw -> qw.ge("last_login", "2023-01-01") .or().gt("login_count", 100));

6. 实际项目中的应用案例

6.1 电商商品筛选系统

在一个电商后台,我们需要实现这样的商品筛选:

  • 分类为电子产品
  • 价格在1000-5000之间
  • 并且(是新品或评分大于4.5)

用QueryWrapper实现如下:

QueryWrapper<Product> wrapper = new QueryWrapper<>(); wrapper.eq("category", "电子产品") .between("price", 1000, 5000) .and(qw -> qw.eq("is_new", true).or().gt("rating", 4.5));

这个查询用到了and()和or()的嵌套组合,生成的SQL既清晰又高效。

6.2 人力资源管理系统

在员工查询功能中,需要支持这样的条件:

  • 部门为研发部或测试部
  • 并且(职称为高级工程师或工作年限大于3年)

实现代码:

QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.and(qw -> qw.eq("dept", "研发部").or().eq("dept", "测试部")) .and(qw -> qw.eq("title", "高级工程师").or().gt("work_years", 3));

这种写法既保持了代码的可读性,又准确表达了复杂的业务逻辑。

6.3 内容管理系统

在文章管理后台,常见的查询需求如:

  • 状态为已发布
  • 并且(创建时间在最近7天或阅读量大于1000)
  • 并且(标签包含Java或标签包含Spring)

QueryWrapper实现:

QueryWrapper<Article> wrapper = new QueryWrapper<>(); wrapper.eq("status", "已发布") .and(qw -> qw.ge("create_time", LocalDate.now().minusDays(7)) .or().gt("view_count", 1000)) .and(qw -> { qw.like("tags", "Java").or().like("tags", "Spring"); });

这个例子展示了多层次的嵌套组合,每个括号都对应着业务逻辑中的一个明确分组。

http://www.gsyq.cn/news/1556125.html

相关文章:

  • 害怕字体侵权?设计师要先弄清字体版权查询、免费商用字体和安全用字方法
  • 每周冲刺
  • 2026无锡黄金回收机构资质测评|正规持证商家甄别与优选攻略 - 奢侈品回收评测
  • 2026编程专业笔记本电脑推荐,全天候编码不插电
  • 跨越数据孤岛:从OneNote/印象笔记到Joplin的完整迁移指南
  • GEO优化可以批量覆盖行业关键词吗
  • 团队博文06项目总结
  • 张家口车灯升级维修哪家专业?幻影车灯深耕行业15年解决各类大灯疑难问题 - 速递信息
  • 海南省高口碑黄金铂金回收白银回收实体老店排行 5 家靠谱门店电话地址全收录
  • 2026成都黄金出手全攻略:行情周期判断、验金要点、结算避坑全解析 - 奢侈品回收评测
  • Windows下CMake交叉编译:破解“无法编译简单测试程序”的困局
  • QuickLook Office预览插件完整指南:3秒快速查看Word、Excel、PPT文件
  • 转行学充电桩维修培训 高口碑正规培训机构选这家 - 湖南阳光技术
  • 6大核心技术:基于ROS的KUKA机械臂智能搬运系统
  • 鸿蒙 ArkUI 可伸缩侧边导航栏布局技术详解 —— 基于 AnimatedContainer 的管理后台实践
  • 终极SPT-AKI存档编辑器:5步掌握离线塔科夫角色修改技巧
  • DLSS Swapper完全指南:解锁NVIDIA显卡性能潜能的终极工具
  • 杭州买猫买狗去哪看?梦宠山庄实地体验分享 - 园友3800037
  • FlicFlac:Windows上最轻量的免费音频转换终极指南
  • MPV PlayKit:让视频播放体验从“能用“到“惊艳“的完整解决方案
  • VSCode中接入Claude Code调用DeepSeek:3步配置+2个调试技巧
  • Android 14/15 Root终极指南:Magisk完整安装与配置教程
  • 杭州想养猫狗先看看,梦宠山庄探店记录 - 园友3800037
  • 从CIE1931色度图到黑体轨迹:色彩科学的可视化基石
  • WorkBuddy入门
  • Pixelle-Video:让AI成为你的视频创作搭档,3分钟从想法到成片
  • 2026佛山同城宠物售卖评分榜实测|五区靠谱繁育庄园测评,榜首高明润博宠物庄园全解析 - 吉林同城获客
  • 杭州宠物店怎么选?梦宠山庄到店体验参考 - 园友3800037
  • 烯酰吗啉农药残留检测卡快速检测果蔬中的烯酰吗啉农药残留
  • 杭州买猫买狗实用攻略:梦宠山庄等4家门店整理 - 园友3800037