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;
}
}