QueryWrapper 是 MyBatis-Plus 框架中的一个核心类,用于以对象化的方式构建 SQL 查询条件。MyBatis-Plus 是一个基于 MyBatis 的增强工具,旨在简化数据库操作,而 QueryWrapper 正是其提供的一个查询构造器。通过链式调用,开发者可以灵活、直观地构造复杂的 SQL 查询,而无需手动编写 SQL 语句。
在传统的 MyBatis 中,查询条件通常需要在 XML 文件中编写 SQL,或者通过字符串拼接生成动态 SQL。这种方式在处理复杂或动态查询时容易出错,且代码可读性较差。QueryWrapper 的出现解决了这些问题,它通过方法调用构建查询条件,不仅提高了代码的安全性(避免 SQL 注入),还让查询逻辑更加清晰。
QueryWrapper 通常与实体类绑定,通过泛型指定。例如,对于一个 User
实体类,可以这样创建:
QueryWrapper<User> wrapper = new QueryWrapper<>();
这里的 User
就是我们的实体类,代表数据库中的一张表。
QueryWrapper 提供了丰富的条件构造方法,例如:
eq
:等于ne
:不等于gt
:大于like
:模糊匹配in
:在某个集合中这些方法支持链式调用,可以轻松组合多个条件。例如:
wrapper.eq("age", 18).like("name", "John");
构造好 QueryWrapper 后,将其传递给 MyBatis-Plus 的 Mapper 接口方法(如 selectList
、selectOne
等)来执行查询。例如:
List<User> users = userMapper.selectList(wrapper);
这样就会返回满足条件的用户列表。
这些方法用于指定字段与值之间的关系,通常以数据库列名和对应的值作为参数,是构建查询条件的基础。
eq
- 等于column
:字段名(字符串类型,对应数据库列名)。value
:要匹配的值(可以是任意类型,如整数、字符串等)。wrapper.eq("age", 18);
// WHERE age = 18
=
连接,适用于简单的相等条件。ne
- 不等于column
:字段名。value
:不匹配的值。wrapper.ne("age", 18);
// WHERE age != 18
!=
或 <>
表示不等于。gt
- 大于column
:字段名。value
:比较的下限值。wrapper.gt("age", 18);
// WHERE age > 18
ge
- 大于等于column
:字段名。value
:比较的下限值。wrapper.ge("age", 18);
// WHERE age >= 18
lt
- 小于column
:字段名。value
:比较的上限值。wrapper.lt("age", 30);
// WHERE age < 30
le
- 小于等于column
:字段名。value
:比较的上限值。wrapper.le("age", 30);
// WHERE age <= 30
between
- 在某个范围内column
:字段名。val1
:范围下限。val2
:范围上限。wrapper.between("age", 18, 30);
// WHERE age BETWEEN 18 AND 30
ge("age", 18).le("age", 30)
。notBetween
- 不在某个范围内column
:字段名。val1
:范围下限。val2
:范围上限。wrapper.notBetween("age", 18, 30);
// WHERE age NOT BETWEEN 18 AND 30
like
- 模糊匹配%
)。column
:字段名。value
:要匹配的子字符串。wrapper.like("name", "John");
// WHERE name LIKE '%John%'
%
表示任意字符的通配符,适合文本搜索。notLike
- 不包含某个字符串column
:字段名。value
:不匹配的子字符串。wrapper.notLike("name", "John");
// WHERE name NOT LIKE '%John%'
likeLeft
- 左模糊匹配%
)。column
:字段名。value
:结尾字符串。wrapper.likeLeft("name", "son");
// WHERE name LIKE '%son'
likeRight
- 右模糊匹配%
)。column
:字段名。value
:开头字符串。wrapper.likeRight("name", "Jo");
// WHERE name LIKE 'Jo%'
in
- 在某个集合中column
:字段名。value
:集合(如 List
或数组)。wrapper.in("id", Arrays.asList(1, 2, 3));
// WHERE id IN (1, 2, 3)
notIn
- 不在某个集合中column
:字段名。value
:集合。wrapper.notIn("id", Arrays.asList(1, 2, 3));
// WHERE id NOT IN (1, 2, 3)
isNull
- 为空NULL
。column
:字段名。NULL
的记录,例如查找没有邮箱的用户。wrapper.isNull("email");
// WHERE email IS NULL
isNotNull
- 不为空NULL
。column
:字段名。NULL
的记录,例如查找有邮箱的用户。wrapper.isNotNull("email");
// WHERE email IS NOT NULL
这些方法用于组合多个条件,支持 AND
和 OR
逻辑,增强查询的灵活性。
and
- AND 条件AND
逻辑,连接另一个条件。Consumer
,用于指定子条件。AND
连接,例如查找年龄为 18 且名字包含 “John” 的用户。wrapper.eq("age", 18).and(w -> w.like("name", "John"));
// WHERE age = 18 AND name LIKE '%John%'
or
- OR 条件OR
逻辑,连接另一个条件。OR
连接,例如查找年龄为 18 或 20 的用户。wrapper.eq("age", 18).or().eq("age", 20);
// WHERE age = 18 OR age = 20
nested
- 嵌套条件wrapper.nested(w -> w.eq("age", 18).or().eq("age", 20))
.like("name", "John");
// WHERE (age = 18 OR age = 20) AND name LIKE '%John%'
这些方法用于指定查询结果的排序方式。
orderByAsc
- 升序排序columns
:一个或多个字段名。wrapper.orderByAsc("age");
// ORDER BY age ASC
orderByDesc
- 降序排序columns
:一个或多个字段名。wrapper.orderByDesc("age");
// ORDER BY age DESC
orderBy
- 自定义排序condition
:布尔值,是否应用排序。isAsc
:布尔值,是否升序。columns
:字段名。wrapper.orderBy(true, true, "age");
// ORDER BY age ASC
这些方法用于控制查询返回的列,优化数据传输。
select
- 指定查询字段columns
:一个或多个字段名。wrapper.select("id", "name");
// SELECT id, name FROM user
last
- 自定义 SQL 片段sql
:SQL 字符串。wrapper.last("LIMIT 10");
// 在 SQL 末尾添加 LIMIT 10
apply
- 动态 SQL 片段sql
:SQL 片段。args
:占位符参数。wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "2023-01-01");
// WHERE date_format(create_time, '%Y-%m-%d') = '2023-01-01'
假设有一个 User
表,包含 id
、name
、age
和 email
字段,以下是一个综合使用常见方法的查询:
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age", 18) // 年龄 >= 18
.like("name", "John") // 名字包含 "John"
.isNotNull("email") // 邮箱不为空
.orderByDesc("age") // 按年龄降序
.select("id", "name", "age"); // 只查询 id、name、age 字段
List<User> users = userMapper.selectList(wrapper);
生成 SQL:
SELECT id, name, age
FROM user
WHERE age >= 18
AND name LIKE '%John%'
AND email IS NOT NULL
ORDER BY age DESC
MyBatis-Plus 提供了多种 Wrapper 类,各有侧重:
QueryWrapper
:专注于构建 SELECT 查询的条件。UpdateWrapper
:用于构建 UPDATE 语句,支持条件和 SET 子句。UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", 1).set("age", 20); // UPDATE user SET age = 20 WHERE id = 1
LambdaQueryWrapper
:QueryWrapper 的 Lambda 版本,使用 Lambda 表达式指定字段。LambdaUpdateWrapper
:UpdateWrapper 的 Lambda 版本。LambdaQueryWrapper 使用 Lambda 表达式,避免了硬编码字段名。例如:
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(User::getAge, 18); // 使用方法引用指定字段
这种方式更安全,因为字段名由编译器检查,避免拼写错误。
查询年龄等于 18 岁的用户:
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("age", 18);
List<User> users = userMapper.selectList(wrapper);
生成的 SQL:
SELECT * FROM user WHERE age = 18
查询年龄在 18 到 30 岁之间,且名字包含 “John” 的用户,按年龄降序排序:
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 18, 30)
.like("name", "John")
.orderByDesc("age");
List<User> users = userMapper.selectList(wrapper);
生成的 SQL:
SELECT * FROM user WHERE age BETWEEN 18 AND 30 AND name LIKE '%John%' ORDER BY age DESC
根据传入的参数动态构建条件:
public List<User> searchUsers(Integer minAge, Integer maxAge, String name) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
if (minAge != null) {
wrapper.ge("age", minAge);
}
if (maxAge != null) {
wrapper.le("age", maxAge);
}
if (name != null && !name.isEmpty()) {
wrapper.like("name", name);
}
return userMapper.selectList(wrapper);
}
这段代码使用了MyBatis Plus的QueryWrapper来构建动态查询条件。根据参数的值,会生成不同的SQL语句。
默认情况(所有参数都为null或空):
searchUsers(null, null, null);
生成的SQL语句将不会有任何where条件:
SELECT * FROM user
只有minAge不为null:
searchUsers(18, null, null);
生成的SQL语句将包含最小年龄条件:
SELECT * FROM user WHERE age >= 18
只有maxAge不为null:
searchUsers(null, 30, null);
生成的SQL语句将包含最大年龄条件:
SELECT * FROM user WHERE age <= 30
只有name不为null且不为空字符串:
searchUsers(null, null, "张三");
生成的SQL语句将包含名字模糊查询条件(使用LIKE):
SELECT * FROM user WHERE name LIKE '%张三%'
组合条件(minAge和maxAge都不为null):
searchUsers(18, 30, null);
生成的SQL语句将包含年龄范围条件:
SELECT * FROM user WHERE age >= 18 AND age <= 30
组合条件(minAge和name都不为null):
searchUsers(18, null, "张三");
生成的SQL语句将包含最小年龄和名字模糊查询条件:
SELECT * FROM user WHERE age >= 18 AND name LIKE '%张三%'
组合条件(maxAge和name都不为null):
searchUsers(null, 30, "张三");
生成的SQL语句将包含最大年龄和名字模糊查询条件:
SELECT * FROM user WHERE age <= 30 AND name LIKE '%张三%'
所有参数都不为null或空:
searchUsers(18, 30, "张三");
生成的SQL语句将包含所有条件:
SELECT * FROM user WHERE age >= 18 AND age <= 30 AND name LIKE '%张三%'
查询年龄等于 18 且名字包含 “John” 的用户:
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(User::getAge, 18)
.like(User::getName, "John");
List<User> users = userMapper.selectList(lambdaWrapper);
@TableField
注解指定了映射)。isNull
或 isNotNull
方法来明确处理 NULL 值。QueryWrapper 是 MyBatis-Plus 中一个强大且灵活的工具,通过链式调用和对象化的方式,开发者可以轻松构建 SQL 查询条件。它不仅提高了开发效率,还增强了代码的可读性和安全性。无论是简单查询还是复杂动态条件,QueryWrapper 都能胜任。如果我们需要更安全的字段引用,可以选择 LambdaQueryWrapper。