MyBatis-Plus QueryWrapper 终极指南:语法详解与避坑实践
在MyBatis-Plus的日常开发中,QueryWrapper作为条件构造器的核心角色,掌握了它的使用技巧就等于掌握了高效数据库操作的钥匙。本文将全面解析QueryWrapper的所有语法细节,并附上实际开发中必须警惕的注意事项。
一、QueryWrapper 核心语法大全
1. 基础比较操作
// 等于
qw.eq("name", "John");
// 不等于
qw.ne("age", 30);
// 大于
qw.gt("price", 100);
// 大于等于
qw.ge("create_time", "2023-01-01");
// 小于
qw.lt("stock", 50);
// 小于等于
qw.le("discount", 0.8);
2. 范围查询
// BETWEEN
qw.between("age", 18, 30);
// NOT BETWEEN
qw.notBetween("salary", 5000, 10000);
// IN
qw.in("department_id", Arrays.asList(1, 3, 5));
// NOT IN
qw.notIn("status", 0, 4);
// IN (SQL子查询)
qw.inSql("role_id", "SELECT id FROM role WHERE level > 3");
3. 模糊查询
// 全模糊:%value%
qw.like("title", "紧急");
// 左模糊:%value
qw.likeLeft("code", "A001");
// 右模糊:value%
qw.likeRight("phone", "138");
// NOT LIKE
qw.notLike("content", "test");
4. 空值判断
qw.isNull("description");
qw.isNotNull("update_time");
5. 分组与排序
// 分组
qw.groupBy("department", "position");
// 排序
qw.orderByAsc("create_time");
qw.orderByDesc("salary");
qw.orderBy(true, true, "id", "name"); // 多个字段排序
6. 复杂条件组合
// AND 连接
qw.eq("deleted", 0)
.ge("create_time", startDate)
.le("create_time", endDate);
// OR 嵌套
qw.and(wrapper -> wrapper
.eq("type", 1)
.or()
.eq("status", 2)
);
// 动态条件
String keyword = getParam();
qw.like(StringUtils.isNotBlank(keyword), "title", keyword);
7. 自定义SQL片段
// 直接拼接SQL
qw.apply("DATE_FORMAT(create_time,'%Y-%m') = {0}", "2023-08");
// EXISTS 子查询
qw.exists("SELECT 1 FROM user_log WHERE user_id = user.id");
二、LambdaQueryWrapper 类型安全写法
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.eq(User::getName, "John")
.ge(User::getAge, 18)
.between(User::getCreateTime, start, end);
三、避坑指南(重要!)
1. SQL注入风险
// 危险!直接拼接字符串
qw.apply("category_id = " + categoryId);
// ✅ 正确写法(使用预编译)
qw.apply("category_id = {0}", categoryId);
2. 空值处理原则
// 错误:空值会导致 WHERE name=null
qw.eq(String name, request.getName());
// ✅ 正确:动态条件
qw.eq(StringUtils.isNotBlank(name), "name", name);
3. 索引失效场景
// 导致索引失效的写法
qw.likeLeft("mobile", "13800138");
// ✅ 建议:右模糊保持索引有效性
qw.likeRight("mobile", "13800138");
4. 嵌套条件优先级
// 错误:逻辑混乱
qw.eq("A",1).or().eq("B",2).eq("C",3);
// ✅ 正确:明确括号范围
qw.and(wrap -> wrap.eq("A",1).or().eq("B",2))
.eq("C",3);
5. 分页查询陷阱
// 错误:分页+排序缺失
Page<User> page = new Page<>(1,10);
userMapper.selectPage(page, qw);
// ✅ 必须:分页必须指定排序字段
qw.orderByDesc("id");
6. 字段类型匹配
// 错误:字符串比较数字字段
qw.eq("status", "1"); // 数据库status是int
// ✅ 正确:类型严格一致
qw.eq("status", 1);
7. 实体属性映射
// 错误:使用数据库不存在的字段
qw.eq("createTime", value); // 实际字段是create_time
// ✅ 方案1:开启下划线转换
// 在配置中设置:mybatis-plus.configuration.map-underscore-to-camel-case=true
// ✅ 方案2:使用Lambda表达式
qw.eq(User::getCreateTime, value);
四、性能优化建议
- 避免全表扫描:WHERE条件中至少包含一个索引字段
- 控制返回字段:避免
select *qw.select("id", "name"); // 显式指定字段 - 批处理操作:对于大量数据更新使用
updateBatch - 逻辑删除冲突:使用
qw.eq("del_flag",0)会与MP全局逻辑删除配置冲突
五、最佳实践总结
- 优先使用LambdaQueryWrapper:编译期检查字段名有效性
- 复杂查询拆解:超过5个条件的查询建议拆分子方法
- SQL控制台输出:开发环境开启
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl - 组合查询规范:
// 清晰的代码结构 qw.select("id", "name", "age") .eq("deleted", 0) .in("role", Arrays.asList(2,3,5)) .groupBy("department") .having("count(1) > 5") .orderByDesc("create_time");
最后的提醒:永远不要相信前端传递的查询参数,所有传入Wrapper的条件必须经过业务层校验!
通过本文的详细梳理,相信您已全面掌握QueryWrapper的使用精髓。在实际开发中结合具体场景灵活运用这些技巧,将极大提升数据操作效率和代码健壮性。如果有更多特殊场景需求,欢迎在评论区交流讨论!
扩展阅读推荐:
- MyBatis-Plus 官方文档 - 条件构造器
- [深度解析MyBatis-Plus的SQL注入防护机制]
- [企业级项目中Wrapper的架构设计实践]
版权声明:本文为优快云博主「技术老宅」原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
3万+

被折叠的 条评论
为什么被折叠?



