QueryWrapper的使用

QueryWrapper 是 MyBatis-Plus (MP) 中最常用的条件构造器。它允许你通过 Java 代码链式调用来构建 SQL 的 WHERE 子句,而无需手写 XML 或 SQL 字符串。

它的核心语法结构是:

java 复制代码
new QueryWrapper<Entity>()
    .方法名("字段名", 值)
    .方法名("字段名", 值)
    ...;

常用条件构造方法速查表

假设你的实体类是 User,对应数据库表字段为 name, age, email, create_time。

SQL 条件 MP 方法 示例代码 生成的 SQL 片段
等于 (=) eq .eq("name", "张三") WHERE name = '张三'
不等于 (<>) ne .ne("status", 0) WHERE status <> 0
大于 (>) gt .gt("age", 18) WHERE age > 18
大于等于 (>=) ge .ge("age", 18) WHERE age >= 18
小于 (<) lt .lt("age", 60) WHERE age < 60
小于等于 (<=) le .le("age", 60) WHERE age <= 60
模糊查询 (LIKE) like .like("name", "张") WHERE name LIKE '%张%'
左模糊 (LIKE LEFT) likeLeft .likeLeft("name", "三") WHERE name LIKE '%三'
右模糊 (LIKE RIGHT) likeRight .likeRight("name", "张") WHERE name LIKE '张%'
在范围内 (IN) in .in("id", 1, 2, 3) WHERE id IN (1, 2, 3)
不在范围内 (NOT IN) notIn .notIn("id", 1, 2) WHERE id NOT IN (1, 2)
为空 (IS NULL) isNull .isNull("email") WHERE email IS NULL
不为空 (IS NOT NULL) isNotNull .isNotNull("email") WHERE email IS NOT NULL
排序 (ORDER BY) orderByAsc/Desc .orderByDesc("age") ORDER BY age DESC
分组 (GROUP BY) groupBy .groupBy("name") GROUP BY name

实战场景演示:

场景 1:简单组合查询

需求:查询年龄大于 18 岁,且名字中包含"张"的用户,按年龄降序排列。

java 复制代码
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 18)          // age > 18
       .like("name", "张")     // AND name LIKE '%张%'
       .orderByDesc("age");    // ORDER BY age DESC

List<User> users = userMapper.selectList(wrapper);

生成 SQL:

sql 复制代码
SELECT * FROM user WHERE age > 18 AND name LIKE '%张%' ORDER BY age DESC

场景 2:动态条件(最常用! )

需求:前端可能传 name,也可能传 age,也可能都不传。只有当参数不为空时,才加入查询条件。

java 复制代码
public List<User> searchUsers(String name, Integer age) {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    
    // 如果 name 不为空且不是空字符串,则添加 like 条件
    if (StringUtils.isNotBlank(name)) {
        wrapper.like("name", name);
    }
    
    // 如果 age 不为 null,则添加 eq 条件
    if (age != null) {
        wrapper.eq("age", age);
    }
    
    return userMapper.selectList(wrapper);
}

场景 3:使用 Lambda 表达式(推荐 ✅)

优点:防止字段名写错(如 "nmae" 写成 "name"),IDE 有自动提示,重构更安全。

需要使用 LambdaQueryWrapper:

java 复制代码
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

// ...

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "张三")      // 对应 name = '张三'
       .gt(User::getAge, 18)           // 对应 age > 18
       .orderByDesc(User::getCreateTime); // 对应 ORDER BY create_time DESC

List<User> users = userMapper.selectList(wrapper);

注意:User::getName 是方法引用,MP 会自动将其解析为数据库字段名 name。这要求你的实体类遵循 JavaBean 规范(有 getter/setter)

高级用法:嵌套逻辑 (AND / OR)

需求:(name LIKE '张' OR email LIKE 'zhang') AND age > 18

java 复制代码
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.and(w -> w.like("name", "张")
                  .or()
                  .like("email", "zhang"))
       .gt("age", 18);

生成SQL:

sql 复制代码
WHERE (name LIKE '%张%' OR email LIKE '%zhang%') AND age > 18

❗ 常见坑点与注意事项:

1.字段名匹配:

如果使用 QueryWrapper,传入的字符串必须是数据库列名(如 user_name),而不是 Java 属性名(如 userName),除非你配置了驼峰转换。

如果使用 LambdaQueryWrapper,传入的是Java 属性方法引用(如 User::getUserName),MP 会自动转换为数据库列名。强烈推荐后者!

2.空值处理:

eq("name", null) 会生成 name IS NULL。

eq("name", "") 会生成 name = ''。

如果希望值为 null 或空字符串时忽略该条件,可以使用 MP 提供的重载方法:

java

java 复制代码
// 只有当 name 不为 null 且不为空时,才添加 eq 条件
wrapper.eq(StringUtils.isNotBlank(name), "name", name);

3.性能问题:

避免在大表上使用 like "%xxx%"(全表扫描)。

尽量使用索引字段进行查询。

总结:

  • 简单查询:直接用 QueryWrapper 或 LambdaQueryWrapper。
  • 复杂动态查询:优先使用LambdaQueryWrapper + 条件判断,安全且易维护。
  • 超复杂联表查询:建议手写 XML SQL,因为 Wrapper主要服务于单表操作。

使用:

java 复制代码
package com.example.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 👈 导入 Lambda 版本
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public IPage<User> getUserPage(int pageNum, int pageSize) {
        // 1. 创建 Page 对象 (当前页, 每页大小)
        Page<User> page = new Page<>(pageNum, pageSize);

        // 2. 构建查询条件 (使用 LambdaQueryWrapper)
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

        // 👇 示例条件:名字不为空 且 按年龄降序排列
        // 注意:User::getName 对应数据库字段 name,User::getAge 对应 age
        wrapper.isNotNull(User::getName)
                .orderByDesc(User::getAge);

        // 3. 调用 MP 的分页方法
        // baseMapper.selectPage(page, wrapper) 会自动生成 LIMIT 语句
        IPage<User> userPage = this.baseMapper.selectPage(page, wrapper);

        return userPage;
    }
}
相关推荐
AI你一生一世1 小时前
不止于时序存储:DolphinDB 如何成为 AI 时代的工业智能底座
java·人工智能·struts·时序数据库·工业智能·dolphindb·ai基础设施
云-缩影1 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
瑞克-桑切斯2 小时前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
海的透彻6 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat6 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习7 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one7 小时前
算法--构造
java·数据结构·算法
SL_staff7 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff8 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko79 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端