QueryWrapper的使用

QueryWrapperMyBatis-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;
    }
}
相关推荐
Chase_______1 小时前
【Java基础 | 15】集合框架(中):Set、HashSet、TreeSet 与哈希表
java·windows·散列表
摇滚侠1 小时前
Maven 入门+高深 微服务案例 122-125
java·微服务·maven
QuZero2 小时前
Guava Cache Deep Dive
java·后端·算法·guava
人道领域2 小时前
【LeetCode刷题日记】93.复原IP地址
java·开发语言·算法·leetcode
摇滚侠2 小时前
JavaWeb 全套教程 Listener 112-113
java·开发语言·servlet·tomcat·intellij-idea
曹牧2 小时前
Java:Deprecated 是
java·开发语言
用户916842202743 小时前
Spring Boot application.yml 最全避坑与多环境配置
java·后端
kobe_t3 小时前
‌Spring AI
java
骄马之死3 小时前
Spring 核心知识点(IOC + AOP + 事务)
java·后端·spring