MyBatis Plus QueryWrapper:从入门到精通的动态查询构建指南

张开发
2026/4/17 11:33:25 15 分钟阅读

分享文章

MyBatis Plus QueryWrapper:从入门到精通的动态查询构建指南
1. QueryWrapper基础入门第一次接触MyBatis Plus的QueryWrapper时我完全被它的简洁性震惊了。记得以前用原生MyBatis时为了写一个简单的条件查询不得不在XML里写一大堆if标签现在只需要几行Java代码就能搞定。QueryWrapper本质上是一个条件构造器它把SQL查询条件用面向对象的方式封装起来让我们可以用更符合Java习惯的方式来构建查询。先来看个最简单的例子。假设我们有个用户表user要查询所有年龄大于18岁的用户传统方式可能要写SQL语句但用QueryWrapper可以这样QueryWrapperUser wrapper new QueryWrapper(); wrapper.gt(age, 18); ListUser userList userMapper.selectList(wrapper);这段代码读起来就像在说给我创建一个查询包装器条件是age大于18然后执行查询。是不是特别直观QueryWrapper支持的方法非常丰富几乎涵盖了所有SQL条件操作eq等于 ne不等于 gt大于 ge大于等于 lt小于 le小于等于 betweenBETWEEN 值1 AND 值2likeLIKE %值%inIN (v1, v2, ...)我在实际项目中最常用的就是eq和like了。比如要查询名字叫张三的用户wrapper.eq(name, 张三);或者模糊查询名字包含张的用户wrapper.like(name, 张);2. 动态查询构建技巧动态查询是QueryWrapper最强大的特性之一。想象一下电商网站的商品筛选功能用户可能选择价格区间、品牌、分类等各种条件的组合。如果用传统方式我们得写一大堆if-else来拼接SQL而QueryWrapper让这个过程变得异常简单。我常用的动态构建方式有两种。第一种是链式调用QueryWrapperProduct wrapper new QueryWrapper(); wrapper.eq(StringUtils.isNotBlank(category), category, category) .between(priceMin ! null priceMax ! null, price, priceMin, priceMax) .like(StringUtils.isNotBlank(keyword), name, keyword);这里用到了QueryWrapper方法的一个特性很多条件方法都有重载版本第一个参数是boolean类型表示是否应用这个条件。这样就能很优雅地处理用户可能不传某些筛选条件的情况。第二种方式是用Lambda表达式这个在Java 8及以上版本特别方便QueryWrapperUser wrapper new QueryWrapper(); wrapper.lambda() .eq(User::getAge, 18) .like(User::getName, 张);Lambda方式最大的好处是类型安全IDE可以自动补全而且重构字段名时不会出错。我在大型项目中更推荐这种方式虽然写起来稍微长一点但维护性更好。3. 复杂条件组合实战当查询条件变得复杂时QueryWrapper依然能保持代码的清晰度。比如我们要查询(年龄大于18或者名字包含张)并且状态为激活的用户wrapper.and(w - w.gt(age, 18).or().like(name, 张)) .eq(status, 1);对应的SQL大概是WHERE (age 18 OR name LIKE %张%) AND status 1再来看个更复杂的例子查询某个时间段内创建的并且(订单金额大于1000或者使用了优惠券)的订单wrapper.between(create_time, startDate, endDate) .and(w - w.gt(amount, 1000).or().eq(has_coupon, 1));在实际项目中我经常遇到需要嵌套条件的情况。QueryWrapper的and和or方法都接受一个Consumer参数可以无限嵌套这让我们能构建出非常复杂的查询逻辑同时保持代码的可读性。4. 性能优化与最佳实践用了QueryWrapper一段时间后我发现了一些性能优化的技巧。首先是避免在循环中创建QueryWrapper因为每次new一个Wrapper对象都会有些开销。我通常会复用Wrapper对象或者使用方法链在单次操作中完成所有条件设置。第二个重要技巧是注意select语句的字段控制。默认情况下selectList会查询所有字段但很多时候我们只需要部分字段wrapper.select(id, name, age);这样可以减少网络传输和内存占用特别是当表有很多字段但业务只需要几个的时候性能提升很明显。还有一个容易忽略的点是索引使用。QueryWrapper生成的SQL语句会按照条件添加的顺序来构建WHERE子句。为了让查询能用上索引应该把选择性高的条件放在前面// 好的写法user_id有索引且选择性高 wrapper.eq(user_id, 123).like(name, 张); // 不好的写法模糊查询放在前面可能使索引失效 wrapper.like(name, 张).eq(user_id, 123);最后分享一个真实案例我们系统有个分页查询接口原本响应时间要2秒多后来发现是因为用了多个like条件导致全表扫描。优化方法是给这些字段加了全文索引然后改用match against语法响应时间降到了200毫秒以内。虽然这不是QueryWrapper直接提供的功能但提醒我们在使用条件构造器时也要考虑底层数据库的特性。

更多文章