一、wapper 介绍

1、Wrapper 家族

在 MP 中我们可以使用通用 Mapper(BaseMapper)实现基本查询,也可以使用自定义 Mapper(自定义 XML)来实现更高级的查询。

当然也可以结合条件构造器来方便的实现更多的高级查询。

  • Wrapper : 条件构造抽象类,最顶端父类
  • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
  • QueryWrapper : 查询条件封装
  • UpdateWrapper : Update 条件封装
  • AbstractLambdaWrapper : 使用 Lambda 语法
  • LambdaQueryWrapper :用于 Lambda 语法使用的查询 Wrapper
  • LambdaUpdateWrapper : Lambda 更新封装 Wrapper

2、创建测试类

1
2
3
4
5
@SpringBootTest
public class WrapperTests {
@Resource
private UserMapper userMapper;
}

二、QueryWrapper

1、组装查询条件

查询名字中包含 0,年龄大于等于 10 且小于等于 20,email 不为空的用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 查询名字中包含0,年龄大于等于10且小于等于20,email不为空的用户
*/
@Test
public void test1() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.like("name", "0");
// queryWrapper.between("age", 10, 20);
// queryWrapper.isNotNull("email");

// 串联写法
queryWrapper.like("name", "0")
.between("age", 10, 20)
.isNotNull("email");

List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

2、组装排序条件

按年龄降序查询用户,如果年龄相同则按 uid 升序排列

用 DESC 表示按倒序排序 (即:从大到小排序) —降序排列

用 ACS 表示按正序排序 (即:从小到大排序) —升序排列

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 按年龄降序查询用户,如果年龄相同则按uid升序排列
*/
@Test
public void test2() {
QueryWrapper<User> queryWrapper = new QueryWrapper();

queryWrapper.orderByDesc("age").orderByAsc("uid");

List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

3、组装删除条件

删除 email 为空的用户

1
2
3
4
5
6
7
8
9
10
11
/**
* 删除email为空的用户
*/
@Test
public void test3() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");

int result = userMapper.delete(queryWrapper);
System.out.println("删除记录数为:" + result);
}

4、条件的优先级

查询名字中包含 1,且(年龄小于 18 或 email 为空的用户),并将这些用户的年龄设置为 18,邮箱设置为 user@atguigu.com

eq 相等
ne、neq 不相等
gt 大于
lt 小于
gte、ge 大于等于
lte、le 小于等于
not 非
mod 求模

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 查询名字中包含1,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
*/
@Test
public void test4() {
// 组装查询条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "1")
.and(i -> i.lt("age", 18).or().isNull("email"));

// 组装更新条件
User user = new User();
user.setAge(18);
user.setEmail("user@atguigu.com");

// 执行更新
int result = userMapper.update(user, queryWrapper);
System.out.println("更新记录数:" + result);
}

5、组装 select 子句

查询所有用户的用户名和年龄

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 查询所有用户的用户名和年龄
*/
@Test
public void test5() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name", "age");

// select 语句通常会和 selectMaps 一起出现
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}

6、实现子查询

查询 uid 不大于 3 的所有用户的 uid 列表

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 查询uid不大于3的所有用户的uid列表
*/
@Test
public void test6() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 容易引发sql注入,or true
// queryWrapper.inSql("uid", "select uid from t_user where uid <= 3");
queryWrapper.le("uid", 3);

List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

三、UpdateWrapper

查询名字中包含 1,且(年龄小于 18 或 email 为空的用户)

将这些用户的年龄设置为 18,邮箱设置为 user@atguigu.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 查询名字中包含1,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 `user@atguigu.com`
*/
@Test
public void test7() {
// 组装查询条件
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper
.set("age", 18)
.set("email", "user@atguigu.com")
.like("name", "1")
// lambda表达式内的逻辑优先运算
.and(i -> i.lt("age", 18).or().isNull("email"));

// 这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
User user = new User();
int result = userMapper.update(user, updateWrapper);
System.out.println("更新记录数:" + result);
}

四、condition

动态组装查询条件

查询名字中包含张,年龄大于 10 且小于 20 的用户,查询条件来源于用户输入,是可选的(比如用户只输入年龄大于 10 的判断条件,没有输入 20)

我们可以使用带 condition 参数的重载方法构建查询条件,简化代码的编写

mp 框架,在条件构造方法里,都会重载一个 condition 参数;

这个参数的作用是动态判断条件,假如 condition 是 true,则拼接加条件,false 的话,则不拼接加条件;

我们前台传来的动态条件,以前是通过代码判断拼接,现在我们可以直接条件构造方法里写,大大简化代码量;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 查询名字中包含张,年龄大于10且小于20的用户,查询条件来源于用户输入
*/
@Test
public void test8() {
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
// isNotEmpty将空格也作为参数,isNotBlank则排除空格参数
.like(StringUtils.isNotBlank(name), "name", "张")
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);

List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

五、LambdaXxxWrapper

1、LambdaQueryWrapper

查询名字中包含张,年龄大于 10 且小于 20 的用户,查询条件来源于用户输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 查询名字中包含张,年龄大于10且小于20的用户,查询条件来源于用户输入
*/
@Test
public void test9() {

// 定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
// 避免使用字符串表示字段,防止运行时错误
.like(StringUtils.isNotBlank(name), User::getName, "张")
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);

List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

2、LambdaUpdateWrapper

查询名字中包含 1,且(年龄小于 18 或 email 为空的用户),并将这些用户的年龄设置为 18,邮箱设置为 user@atguigu.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 查询名字中包含张,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
*/
@Test
public void test10() {
// 组装查询条件
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper
.set(User::getAge, 18)
.set(User::getEmail, "user@atguigu.com")
.like(User::getName, "张")
.and(i -> i.lt(User::getAge, 18).or().isNull(User::getEmail));

// 这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
User user = new User();
int result = userMapper.update(user, updateWrapper);
System.out.println("更新记录数:" + result);
}