MyBatis-Plus Wrapper 构造器
Administrator
2026-09-27
0 阅读
Wrapper 就是一个用于构造 SQL 语句中 WHERE 条件部分的 Java 工具类 。它让你能够通过链式调用的方式,用 Java 代码拼写出各种复杂的查询、更新、删除条件,从而避免手写繁琐的 SQL 片段。Wrapper 家族主要有两个分支:QueryWrapper(用于查询)和 UpdateWrapper(用于更新),以及它们的 Lambda 版本。
1. Wrapper 继承体系(了解即可) text
Wrapper(顶级接口)
└── AbstractWrapper(抽象类,实现了大部分条件方法)
├── QueryWrapper(用于查询、删除)
├── UpdateWrapper(用于更新,可以 set 字段)
├── LambdaQueryWrapper(Lambda 版 QueryWrapper)
└── LambdaUpdateWrapper(Lambda 版 UpdateWrapper)
在实际开发中,我们通常直接使用 LambdaQueryWrapper 和 LambdaUpdateWrapper ,因为它们能用 Lambda 表达式引用实体类的属性(比如 User::getName),避免写错字段名(字符串形式容易写错或重构时遗漏)。
2. 为什么需要 Wrapper? 假如我们要查一张用户表 user,需要满足以下条件:
年龄在 18~30 之间
性别为男
姓名包含“张”
按年龄降序排序
不用 Wrapper 的话,你需要在 Mapper.xml 里手写 SQL:
xml
<select id="selectUserList" resultType="User">
SELECT * FROM user
WHERE age BETWEEN 18 AND 30
AND gender = '男'
AND name LIKE '%张%'
ORDER BY age DESC
</select>
如果使用 Wrapper,你不用写 XML ,直接在 Java 代码里构造:
java
// 创建条件构造器
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.between(User::getAge, 18, 30)
.eq(User::getGender, "男")
.like(User::getName, "张")
.orderByDesc(User::getAge);
// 直接传入 Mapper 方法执行查询
List<User> users = userMapper.selectList(wrapper);
是不是简洁很多?而且完全避免了 XML 的维护工作。
3. 核心常用方法(以 LambdaQueryWrapper 为例) 🔹 比较条件 方法
说明
示例
eq
等于 =
wrapper.eq(User::getAge, 18) → age = 18
ne
不等于 <>
wrapper.ne(User::getAge, 18) → age <> 18
gt
大于 >
wrapper.gt(User::getAge, 18) → age > 18
ge
大于等于 >=
wrapper.ge(User::getAge, 18)
lt
小于 <
wrapper.lt(User::getAge, 18)
le
小于等于 <=
wrapper.le(User::getAge, 18)
between
在区间内 (包含边界)
wrapper.between(User::getAge, 18, 30) → age BETWEEN 18 AND 30
notBetween
不在区间内
…
in
在集合/数组中
wrapper.in(User::getAge, Arrays.asList(18,20,22))
notIn
不在集合中
…
isNull
字段为 NULL
wrapper.isNull(User::getEmail)
isNotNull
字段不为 NULL
…
🔹 模糊匹配 方法
说明
示例
like
全模糊匹配
wrapper.like(User::getName, "张") → name LIKE '%张%'
likeLeft
左模糊
wrapper.likeLeft(User::getName, "张") → name LIKE '%张'
likeRight
右模糊
wrapper.likeRight(User::getName, "张") → name LIKE '张%'
🔹 排序 方法
说明
示例
orderByAsc
升序
wrapper.orderByAsc(User::getAge, User::getId) → ORDER BY age ASC, id ASC
orderByDesc
降序
wrapper.orderByDesc(User::getAge)
orderBy
指定顺序
wrapper.orderBy(true, true, User::getAge) 第一个参数是否排序,第二个是否升序
🔹 逻辑组合(AND / OR) 默认情况下,多个条件是 AND 连接。如果要使用 OR ,可以调用 or() 方法。
AND 示例(默认) :
java
wrapper.eq(User::getGender, "男")
.gt(User::getAge, 18);
// SQL: WHERE gender = '男' AND age > 18
OR 示例 :
java
wrapper.eq(User::getGender, "男")
.or()
.eq(User::getGender, "女");
// SQL: WHERE gender = '男' OR gender = '女'
复杂 OR 嵌套(推荐用 lambda 表达式) :
java
wrapper.eq(User::getStatus, 1)
.and(w -> w.eq(User::getAge, 18).or().eq(User::getAge, 20));
// SQL: WHERE status = 1 AND ( age = 18 OR age = 20 )
🔹 指定查询字段 java
wrapper.select(User::getId, User::getName, User::getAge);
// 只查询这三个字段,SQL 为 SELECT id,name,age FROM ...
🔹 分组和 having java
wrapper.groupBy(User::getGender)
.having("AVG(age) > {0}", 25);
// SQL: GROUP BY gender HAVING AVG(age) > 25
🔹 其他常用方法 4. QueryWrapper 与 LambdaQueryWrapper 的区别 强烈建议只用 Lambda 版本 。
5. UpdateWrapper 的用法 UpdateWrapper 除了能构造 WHERE 条件,还能指定 SET 子句 ,常用于更新部分字段。
示例1:更新字段值(不通过实体对象) java
// 将所有 age > 30 的用户的状态改为 0,并且年龄增加 1
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(User::getStatus, 0)
.setSql("age = age + 1") // 直接写 SQL 片段
.gt(User::getAge, 30);
userMapper.update(null, updateWrapper); // 第一个参数是实体,null表示只更新 set 指定的字段
示例2:条件更新结合实体 java
User user = new User();
user.setStatus(1); // 要更新的字段
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getName, "张三");
userMapper.update(user, wrapper);
// SQL: UPDATE user SET status = 1 WHERE name = '张三'
6. 动态条件:当某个条件为空时不拼接 Wrapper 的方法都提供了带 condition 参数的重载,让你可以控制是否添加该条件。这是开发中最常用的技巧 。
java
// 假如前端传来参数:name(可为空),age(可为空)
public List<User> searchUser(String name, Integer age) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 只有当 name 不为空时,才拼接 name like 条件
wrapper.like(StringUtils.hasText(name), User::getName, name);
// 只有当 age 不为空时,才拼接 age = 条件
wrapper.eq(age != null, User::getAge, age);
return userMapper.selectList(wrapper);
}
这样当前端不传某个参数时,该条件就不会出现在 SQL 中,非常安全便捷。
7. 实战例子 例1:分页 + 动态条件 + 排序 java
@GetMapping("/list")
public IPage<User> listUsers(@RequestParam(required = false) String name,
@RequestParam(required = false) Integer minAge,
@RequestParam(defaultValue = "1") long current,
@RequestParam(defaultValue = "10") long size) {
// 分页对象
Page<User> page = new Page<>(current, size);
// 构造条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.hasText(name), User::getName, name)
.ge(minAge != null, User::getAge, minAge)
.orderByDesc(User::getCreateTime);
// 执行分页查询
return userMapper.selectPage(page, wrapper);
}
例2:批量删除(根据多个 ID) java
List<Long> idList = Arrays.asList(1L, 2L, 3L);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.in(User::getId, idList);
userMapper.delete(wrapper);
// 等价 SQL:DELETE FROM user WHERE id IN (1,2,3)
例3:复杂嵌套查询(年龄>20 并且 (性别男 或者 名字包含“张”)) java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(User::getAge, 20)
.and(w -> w.eq(User::getGender, "男")
.or()
.like(User::getName, "张"));
8. 注意事项与常见坑 不要混用 QueryWrapper 和 LambdaQueryWrapper ,选定一种风格保持统一。
条件构造器只适用于单表操作 。如果需要多表联查,要么手写 SQL(放在 Mapper.xml 里),要么使用 MP 的 @Select 注解或自定义 Mapper 方法,Wrapper 仍然可以作为参数传入(但需注意字段别名)。
or() 方法 会与前面的条件形成括号分组,小心逻辑错误。推荐使用 and(consumer) 或 or(consumer) 显式包裹。
last("limit 1") 等方法会直接拼接到 SQL 末尾,可能与分页插件冲突,且有 SQL 注入风险,尽量用 wrapper.last("limit 1") 仅在测试或特定场景使用。
UpdateWrapper 的 set 方法 如果设置字段值为 null,数据库会更新为 null,除非你配置了字段策略(@TableField(strategy = FieldStrategy.IGNORED))。
总结 Wrapper 是 MyBatis-Plus 的灵魂工具,它让我们用 Java 代码优雅地构造 SQL 条件,极大简化了数据访问层的开发。记住三个核心点:
用 LambdaQueryWrapper 和 LambdaUpdateWrapper
善用带 condition 参数的方法实现动态条件
复杂条件用 .and() / .or() 包裹 Lambda 表达式