视频课程地址:黑马商城项目
上一节:MybatisPlus(一)快速入门
下一节:MybatisPlus(二)核心功能02 — 自定义SQL
本节学习MybatisPlus(MP)的核心功能 — 条件构造器:
Wrapper
AbstractWrapper
详解QueryWrapper
与LambdaQueryWrapper
,以及相关示例UpdateWrapper
与LambdaUpdateWrapper
,以及相关示例
一、Wrapper
MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。
Wrapper
:条件构造器。用于构造复杂SQL语句的。
1.1 Wrapper的继承关系
二、AbstractWrapper详解
以下是 AbstractWrapper
中一些常用方法的介绍:
2.1 实体信息操作方法
getEntity(): T
:用于获取当前条件构造器所关联的实体对象setEntity(T): Children
:用于设置当前条件构造器所关联的实体对象getEntityClass(): Class<T>
:用于获取当前条件构造器所关联的实体类的Class
对象setEntityClass(Class<T>): Children
:用于设置当前条件构造器所关联的实体类的Class
对象
2.2 等值比较方法
eq(boolean, R, Object):Children
:用于构建等于(=
)条件。- 第一个布尔参数用于控制是否添加该条件,第二个参数为数据库字段,第三个参数为要比较的值。
ne(boolean, R, Object):Children
:用于构建不等于(<>
)条件。逻辑同eq
方法。gt(boolean, R, Object):Children
:用于构建大于(>
)条件。逻辑同eq
方法。ge(boolean, R, Object):Children
:用于构建大于等于(>=
)条件。逻辑同eq
方法。lt(boolean, R, Object):Children
:用于构建小于(<
)条件。逻辑同eq
方法。le(boolean, R, Object):Children
:用于构建小于等于(<=
)条件。逻辑同eq
方法。
2.3 多条件等值匹配方法
allEq(boolean, Map<R, V>, boolean): Children
:当第一个布尔参数为true
时,根据Map
中的键值对构建多个等值条件,第三个布尔参数控制对Map
中值为null
的键值对的处理方式,若为true
则构建IS NULL
条件,否则忽略该键值对allEq(boolean, BiPredicate<R, V>, Map<R, V>, boolean): Children
:当第一个布尔参数为true
时,根据Map
中的键值对构建多个等值条件,第二个BiPredicate
参数用于对键值对进行过滤,只有满足BiPredicate
条件的键值对才会用于构建条件,第四个布尔参数控制对Map
中值为null
的键值对的处理方式
2.4 范围比较方法
between(boolean, R, Object, Object):Children
:用于构建BETWEEN...AND...
范围条件。- 第一个布尔参数控制是否添加条件,第二个参数为数据库字段,后两个参数分别为范围的起始和结束值。
notBetween(boolean, R, Object, Object):Children
:用于构建NOT BETWEEN...AND...
范围条件。逻辑同between
方法。
2.5 模糊查询方法
like(boolean, R, Object):Children
:用于构建LIKE
模糊查询条件,会在值前后自动添加%
。notLike(boolean, R, Object):Children
:用于构建NOT LIKE
模糊查询条件。逻辑同like
方法。likeLeft(boolean, R, Object):Children
:用于构建左模糊查询条件,会在值前添加%
。likeRight(boolean, R, Object):Children
:用于构建右模糊查询条件,会在值后添加%
。
2.6 范围查询方法
between(boolean, R, Object, Object): Children
:当布尔参数为true
时,用于构建范围(BETWEEN...AND...
)条件notBetween(boolean, R, Object, Object): Children
:当布尔参数为true
时,用于构建不在某个范围(NOT BETWEEN...AND...
)条件
2.7 模糊查询否定方法
notLikeLeft(boolean, R, Object): Children
:当布尔参数为true
时,用于构建左模糊不匹配(NOT LIKE '%值'
)条件notLikeRight(boolean, R, Object): Children
:当布尔参数为true
时,用于构建右模糊不匹配(NOT LIKE '值%'
)条件
2.8 空值判断方法
isNull(boolean, R):Children
:用于构建字段为空(IS NULL
)的条件。isNotNull(boolean, R):Children
:用于构建字段不为空(IS NOT NULL
)的条件。
2.9 逻辑组合方法
and(Consumer<Children>):Children
:用于添加AND
逻辑的子条件。or():Children
:用于简单的OR
逻辑连接。or(Consumer<Children>):Children
:用于添加带括号的OR
逻辑子条件。
2.10 排序方法
orderByAsc(R...):Children
:用于按指定字段进行升序排序。orderByDesc(R...):Children
:用于按指定字段进行降序排序。
2.11 分组和聚合方法
groupBy(R...):Children
:用于按指定字段进行分组查询。having(String, Object...):Children
:用于添加HAVING
子句,可用于对分组结果进行过滤。
三、QueryWrapper
在父类基础上,扩展了select功能,允许在构造SQL语句时可以指定select哪些字段。
select(String...)
:参数传需要的字段即可,多个字段使用,
间隔。例如:select("id", "username", "info", "balance")
select(List<String>)
:参数传需要的字段的List集合。
四、UpdateWrapper
在父类基础上,扩展了set部分。
红框内的方法是使用字符串的形式把set部分写出来,最后拼到SQL语句中。(比较少见)
setSql(boolean, String)
:- 第一个参数:
true
(后面的SQL语句拼接到SQL语句中)、false
(后面SQL语句会被忽略,不被使用) - 第二个参数:
set
部分的SQL。例如:“
- 第一个参数:
五、使用Lambda语法子类(推荐)
AbstractLambdaaWrapper
LambdaUpdateWrapper
LambdaQueryWrapper
这三个和上面三个作用其实相同,只是扩展了可以使用lambda的写法。
为什么要用Lambda语法?
因为如下方6.3中的查询代码一样,将需要查询的字段名直接硬编码到代码中,这种方式是不推荐的。
LambdaWrapper就是解决这个问题的。
具体怎么使用看下面的第八节
六、案例一:基于QueryWrapper的查询
6.1 案例
红色的SQL语句是我针对这个案例写出的SQL,下面就要使用MP构造相关SQL。
6.2 UserMaper
依旧不用写任何方法
public interface UserMapper extends BaseMapper<User>{
}
6.3 单元测试代码(①)
@Test
void testQueryWrapper() {
// 1. 构建查询条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", "1000");
// 2. 查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
运行结果:
代码解析:
构建查询条件(wrapper)时采用链式编程方式。
new QueryWrapper<User>
:创建QueryWrapper类的实例,并使用方法对构造条件进行丰富,同时传入User
为泛型.select("id", "username", "info", "balance")
:构建SQL的select
部分,指定需要查询的字段.like("username", "o")
:构造where
部分的条件:模糊查询username
字段值带有o
字符串的.ge("balance", "1000")
:构造where
部分的条件:balance
字段大于等于1000的如上的构造条件拼接成SQL即为:
select id, username, info, balance from user where username like CONCAT('%', 'o' ,'%') AND balance >= 1000;
List<User> users = userMapper.selectList(wrapper);
:使用UserMapper
利用这个构造查询并返回User
的列表
1.6.4 单元测试代码(②)
@Test
void testUpdateByQueryWrapper() {
// 1. 要更新的数据
User user = new User();
user.setBalance(2000);
// 2. 更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.eq("username", "jack");
// 3. 执行更新
userMapper.update(user, wrapper);
}
运行结果:
已成功更新数据。
代码解析:
User user = new User();user.setBalance(2000);
:先将需要更新的数据(set
部分字段)写成对象QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");
:再构建SQL语句的WHERE
条件userMapper.update(user, wrapper)
:最后执行更新
七、案例二:基于UpdateWrapper的更新
7.1 案例
7.2 单元测试代码
@Test
void testUpdateWrapper() {
List<Long> idList = List.of(1L, 2L, 3L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql(true, "balance = (balance - 200)")
.in("id", idList);
userMapper.update(null, wrapper);
}
运行结果:
已成功更新数据。
代码解析:
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
:创建一个UpdateWrapper实例.setSql(true, "balance = (balance - 200)")
:手写set
部分的代码(不要set
关键字).in("id", idList)
:这是WHERE
部分的筛选条件userMapper.update(null, wrapper)
:执行修改方法,因为不需要传入User
实体类作为修改对象,所以直接传null
。
八、基于LambdaWrapper查询
8.1 重构6.3的代码
@Test
void testLambdaQueryWrapper() {
// 1. 构建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.select(User::getId, User::getUsername, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, "1000");
// 2. 查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
运行结果与之前的代码效果相同。
代码解析:
举例:将"id"
换成User::getId
。
其实是利用反射,使用函数User::getId
找到对应的字段名,然后拼接到SQL中,从而避免了魔法值和硬编码。
8.2 重构6.4的代码
@Test
void testUpdateByLambdaQueryWrapper() {
// 1. 要更新的数据
User user = new User();
user.setBalance(2000);
// 2. 更新的条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.eq(User::getUsername, "jack");
// 3. 执行更新
userMapper.update(user, wrapper);
}
8.3 重构7.2的代码
@Test
void testLambdaUpdateWrapper() {
List<Long> idList = List.of(1L, 2L, 3L);
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>()
.setSql(true, "balance = (balance - 200)")
.in(User::getId, idList);
userMapper.update(null, wrapper);
}