条件构造器Wrapper
# 条件构造器Wrapper
前言
在 MyBatis-Plus 中,条件构造器是进行查询、更新等操作的重要工具,它提供了灵活的 API 来构建 SQL 条件,并支持链式调用。条件构造器主要包含 Wrapper
、QueryWrapper
、UpdateWrapper
以及 Lambda 表达式相关的构造器。
# 1.Wrapper 介绍
Wrapper
: 条件构造抽象类,最顶端父类AbstractWrapper
: 用于查询条件封装,生成 sql 的 where 条件QueryWrapper
: 查询条件封装UpdateWrapper
: Update 条件封装AbstractLambdaWrapper
: 使用 Lambda 语法LambdaQueryWrapper
:用于 Lambda 语法使用的查询 WrapperLambdaUpdateWrapper
: Lambda 更新封装 Wrapper
# 2. QueryWrapper 详解
在 MyBatis-Plus 中,QueryWrapper
是一个非常常用的条件构造器,用于构建复杂的查询条件。它支持链式调用,可以通过简单的代码构造出复杂的 SQL 查询。本文将详细总结如何使用 QueryWrapper
进行各种查询操作。
# 1. QueryWrapper 对象的创建
创建 QueryWrapper
对象非常简单,可以通过构造函数来实现:
// 创建一个空的 QueryWrapper 对象
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
2
# 2. 基本查询条件
QueryWrapper
提供了常用的基本查询条件,例如等于、不等于、大于、小于等:
queryWrapper.eq("age", 25); // 等于
queryWrapper.ne("status", "inactive"); // 不等于
queryWrapper.gt("salary", 5000); // 大于
queryWrapper.lt("age", 30); // 小于
2
3
4
API 说明:
.eq(String column, Object value)
:等于。.ne(String column, Object value)
:不等于。.gt(String column, Object value)
:大于。.lt(String column, Object value)
:小于。
# 3. 模糊查询条件
可以使用 like
和 notLike
方法实现模糊查询:
queryWrapper.like("username", "John"); // 模糊查询,匹配包含 "John" 的用户名
queryWrapper.notLike("email", "gmail"); // 模糊查询,排除包含 "gmail" 的邮箱
2
API 说明:
.like(String column, String value)
:模糊查询,匹配包含指定值的字段。.notLike(String column, String value)
:模糊查询,不匹配包含指定值的字段。
# 4. 组合查询条件
QueryWrapper
支持多个查询条件的组合,例如 AND、OR 等逻辑操作:
queryWrapper.and(wrapper -> wrapper.eq("age", 25).ne("status", "inactive"))
.or(wrapper -> wrapper.like("username", "John").gt("salary", 5000));
2
注意:在组合查询中,使用了 Lambda 表达式的条件会优先执行。
# 5. 自定义 SQL 片段
如果 QueryWrapper
内置的条件方法无法满足需求,可以通过 apply
方法自定义 SQL 片段:
queryWrapper.apply("date_format(create_time,'%Y-%m-%d') = {0}", "2023-08-25");
API 说明:
.apply(String sql, Object... params)
:插入自定义 SQL 片段,参数可以使用占位符。
# 6. 排序和分页
可以使用 orderBy
方法指定排序字段,使用 last
方法添加自定义 SQL 片段:
queryWrapper.orderByAsc("create_time"); // 按照创建时间升序排序
queryWrapper.last("LIMIT 5"); // 限制返回 5 条记录
2
API 说明:
.orderByAsc(String... columns)
:按指定列升序排序。.orderByDesc(String... columns)
:按指定列降序排序。.last(String lastSql)
:拼接自定义的 SQL 片段。
# 7. 链式调用
QueryWrapper
的设计支持链式调用,使得条件构造更加简洁易读:
queryWrapper.eq("age", 30)
.like("name", "John")
.orderByAsc("create_time")
.last("LIMIT 10");
2
3
4
# 8. 其他查询条件
除了基本的条件,MyBatis-Plus 还提供了许多其他查询条件,例如 isNull
、isNotNull
、in
、notIn
等:
queryWrapper.isNull("email"); // 查询 email 为空的记录
queryWrapper.in("status", Arrays.asList("active", "pending")); // 查询状态为 active 或 pending 的记录
2
# 9. 指定查询返回的字段
通过 select
方法可以指定查询时要返回的字段:
queryWrapper.select("username", "age", "email"); // 只返回用户名、年龄、邮箱字段
API 说明:
.select(String... columns)
:指定查询时要返回的字段。
# 10. QueryWrapper 使用示例
以下是一个完整的示例,演示如何使用 QueryWrapper
进行查询操作:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age", 30)
.like("name", "John")
.orderByAsc("create_time")
.last("LIMIT 10");
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
2
3
4
5
6
7
8
生成的 SQL:
SELECT * FROM user WHERE age = 30 AND name LIKE '%John%' ORDER BY create_time ASC LIMIT 10
# 11. 复杂场景的查询示例
# a. 组装查询条件
public void testComplexQuery() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("username", "a")
.between("age", 20, 30)
.isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
2
3
4
5
6
7
8
9
执行的 SQL:
SELECT uid, username, age, email FROM t_user WHERE username LIKE '%a%' AND age BETWEEN 20 AND 30 AND email IS NOT NULL
# b. 组装排序条件
public void testOrderBy() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
2
3
4
5
6
7
执行的 SQL:
SELECT uid, username, age, email FROM t_user ORDER BY age DESC, id ASC
# c. 组装删除条件
public void testDeleteByCondition() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
int result = userMapper.delete(queryWrapper);
System.out.println(result > 0 ? "删除成功!" : "删除失败!");
}
2
3
4
5
6
7
执行的 SQL:
DELETE FROM t_user WHERE email IS NULL
# d. 实现子查询
public void testSubQuery() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "SELECT id FROM t_user WHERE id <= 100");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
2
3
4
5
6
7
执行的 SQL:
SELECT * FROM t_user WHERE id IN (SELECT id FROM t_user WHERE id <= 100)
# 3. UpdateWrapper 详解
UpdateWrapper
是 MyBatis-Plus 提供的用于构建更新条件的工具类。它不仅继承了 QueryWrapper
的所有条件构造功能,还增加了 set
方法用于设置更新字段及其对应的值。下面将详细介绍如何使用 UpdateWrapper
进行更新操作。
# 3.1 基本使用
UpdateWrapper
允许你像 QueryWrapper
一样构建查询条件,同时可以设置更新的字段和新值:
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("age", 25) // 等于条件
.set("email", "newemail@example.com"); // 设置新值
2
3
API 说明:
.eq(String column, Object value)
:用于指定查询条件。.set(String column, Object value)
:用于指定要更新的字段及新值。
# 3.2 复杂条件更新
在实际开发中,经常需要根据复杂条件进行更新操作。UpdateWrapper
支持使用 and
、or
、like
等方法来构建复杂的条件逻辑:
public void updateUser() {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.like("username", "a") // 模糊查询用户名中包含 "a"
.and(i -> i.gt("age", 20).or().isNull("email")) // 年龄大于 20 或邮箱为空
.set("email", "updatedemail@example.com"); // 设置新邮箱
int result = userMapper.update(null, updateWrapper); // 执行更新
System.out.println(result > 0 ? "修改成功!" : "修改失败!");
}
2
3
4
5
6
7
8
9
执行的 SQL:
UPDATE user SET email='updatedemail@example.com' WHERE (username LIKE '%a%' AND (age > 20 OR email IS NULL))
# 3.3 设置更新字段的示例
通过 set
方法可以直接设置要更新的字段及其对应的新值:
updateWrapper.set("email", "newemail@example.com") // 设置 email 字段的新值
.set("status", "active"); // 设置 status 字段为 active
2
这种方式在需要更新多个字段时特别简洁。
# 4. 条件构造中的 condition
参数
在实际开发中,查询条件往往来源于用户输入,可能是可选的。在这种情况下,需要根据用户是否选择了某个条件来决定是否将其加入查询中。MyBatis-Plus 提供了 condition
参数用于简化这类条件构造。
# 4.1 传统方式的条件构造
传统方式中,需要手动判断每个条件是否需要添加到查询中:
public void conditionalQuery() {
String username = "a";
Integer ageBegin = null;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
queryWrapper.like("username", username);
}
if (ageBegin != null) {
queryWrapper.ge("age", ageBegin);
}
if (ageEnd != null) {
queryWrapper.le("age", ageEnd);
}
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 4.2 使用 condition
参数简化代码
MyBatis-Plus 提供了带 condition
参数的重载方法,可以简化条件判断的代码:
public void conditionalQuerySimplified() {
String username = "a";
Integer ageBegin = null;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(username), "username", username) // 当 username 不为空时,添加 like 条件
.ge(ageBegin != null, "age", ageBegin) // 当 ageBegin 不为 null 时,添加 >= 条件
.le(ageEnd != null, "age", ageEnd); // 当 ageEnd 不为 null 时,添加 <= 条件
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
2
3
4
5
6
7
8
9
10
11
12
13
API 说明:
.like(boolean condition, String column, Object value)
:当condition
为true
时添加 like 查询条件。.ge(boolean condition, String column, Object value)
:当condition
为true
时添加大于等于条件。.le(boolean condition, String column, Object value)
:当condition
为true
时添加小于等于条件。
通过使用 condition
参数,可以大幅简化条件判断逻辑,提升代码的可读性。
# 4.3 condition
参数示意图
该示意图展示了 condition
参数的作用:根据用户的输入动态决定是否添加查询条件。
# 5. LambdaQueryWrapper
LambdaQueryWrapper
是 MyBatis-Plus 提供的条件构造器,功能与 QueryWrapper
相同,但提供了 Lambda 表达式的语法,使得代码更加安全和易读。
主要特点:
- 使用 Lambda 表达式:通过 Lambda 表达式直接引用实体类中的字段,避免了手动硬编码字段名的风险。
- 方法引用支持:除了 Lambda 表达式,还支持使用方法引用,使代码更加简洁。
- 避免字段名错误:在使用过程中,字段名由编译器自动解析,避免了拼写错误。
public void testLambdaQuery() {
String username = "a";
Integer ageBegin = null;
Integer ageEnd = 30;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
2
3
4
5
6
7
8
9
10
11
# 6. LambdaUpdateWrapper
LambdaUpdateWrapper
与 UpdateWrapper
类似,功能相同,但支持使用 Lambda 表达式来构建更新条件和设置字段值。
使用示例:
public void testLambdaUpdate() {
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.like(User::getName, "a")
.and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail))
.set(User::getName, "小黑")
.set(User::getEmail, "abc@atguigu.com");
int result = userMapper.update(null, updateWrapper);
System.out.println("result:" + result);
}
2
3
4
5
6
7
8
9
主要特点:
- 安全性更高:字段名由编译器解析,减少了拼写错误的风险。
- 代码更加简洁和直观:使用 Lambda 表达式和方法引用使得代码逻辑更加清晰。