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;
    }
}
相关推荐
frjc3 分钟前
如何在 IDEA 中打开并运行已有Java项目
java·ide·intellij-idea
java_nnnn36 分钟前
文件操作和IO
java
lsylalalala37 分钟前
多线程(4)
java·开发语言·多线程
吴声子夜歌1 小时前
Guava——散列
java·guava
用户3126874877201 小时前
AQS 到底怎么排队的?CLH 队列、state 与条件变量全链路拆解
java
Json____1 小时前
springboot开发高校选课管理系统:从零构建前后端分离的全栈实践
java·spring boot·后端·毕业设计·毕设·wwwoop.com
xcl09251 小时前
民宿预约系统开发实战:从需求分析到上线部署全流程解析
java·spring boot
步行cgn2 小时前
为何以继承方式引入SpringBoot
java·spring boot·后端
CoderYanger2 小时前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
禾高网络2 小时前
养老系统开发:背景、架构与养老行业展望
java·大数据·人工智能·小程序·架构