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;
    }
}
相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi3 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号3 天前
java函数式编程--入门基础
java·编程·函数式编程