MyBatis-Plus 条件构造器(Wrapper)全解析
一、Wrapper 体系介绍
Wrapper 是 MyBatis-Plus 中用于构建查询条件的抽象类,其继承结构如下:
- Wrapper:条件构造抽象类,最顶端父类
- AbstractWrapper:用于查询条件封装,生成 SQL 的 WHERE 条件
- QueryWrapper:查询条件封装
- UpdateWrapper:更新条件封装
- AbstractLambdaWrapper:使用 Lambda 语法构建条件
- LambdaQueryWrapper:Lambda 风格的查询 Wrapper
- LambdaUpdateWrapper:Lambda 风格的更新 Wrapper
核心区别:
- QueryWrapper/UpdateWrapper:通过字符串指定字段名
- LambdaQueryWrapper/LambdaUpdateWrapper:通过 Lambda 表达式指定字段(User::getName),避免硬编码,更安全
二、QueryWrapper 实战
QueryWrapper 主要用于构建查询条件,以下是常见用法示例:
1. 组装查询条件
@Test
public void testQueryWrapper1() {
// 查询年龄大于20且邮箱不为空的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20) // 年龄>20
.isNotNull("email"); // 邮箱不为空
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
2. 组装排序条件
@Test
public void testQueryWrapper2() {
// 查询所有用户,按年龄降序排列,若年龄相同则按id升序排列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age") // 按年龄降序
.orderByAsc("id"); // 按id升序
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
3. 组装删除条件
@Test
public void testQueryWrapper3() {
// 删除邮箱为空的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email"); // 邮箱为空
int result = userMapper.delete(queryWrapper);
System.out.println("受影响的行数:" + result);
}
4. 组装 select 子句(指定查询字段)
@Test
public void testQueryWrapper5() {
// 只查询id、name和age字段
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "name", "age") // 指定查询的字段
.gt("age", 20); // 年龄>20
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
5. 实现子查询
@Test
public void testQueryWrapper6() {
// 查询id小于等于3的用户信息(使用子查询)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "select id from user where id <= 3");
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
三、UpdateWrapper 实战
UpdateWrapper 专门用于构建更新操作的条件,支持更灵活的 SET 语句构建:
1. 基本更新示例
@Test
public void testUpdateWrapper1() {
// 将名字中包含"张"的用户年龄改为25,邮箱改为zhang@example.com
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.like("name", "张") // 条件:name包含"张"
.set("age", 25) // 设置age=25
.set("email", "zhang@example.com"); // 设置email
int result = userMapper.update(null, updateWrapper);
System.out.println("受影响的行数:" + result);
}
2. 复杂条件更新
@Test
public void testUpdateWrapper2() {
// 年龄小于20或邮箱为空的用户,年龄改为22
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.lt("age", 20)
.or()
.isNull("email")
.set("age", 22);
int result = userMapper.update(null, updateWrapper);
System.out.println("受影响的行数:" + result);
}
四、条件判断(condition)
在实际开发中,查询条件往往来自用户输入,具有不确定性。我们需要根据用户是否输入来动态组装条件,避免无效条件影响查询结果。
传统思路(繁琐)
@Test
public void testCondition1() {
// 可能为null的查询条件(用户输入)
String username = null; // 用户未输入用户名
Integer ageBegin = 10; // 最小年龄
Integer ageEnd = 24; // 最大年龄
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 仅当username不为空时才添加模糊查询
if (StringUtils.isNotBlank(username)) {
queryWrapper.like("name", username);
}
// 仅当ageBegin不为空时才添加大于等于条件
if (ageBegin != null) {
queryWrapper.ge("age", ageBegin);
}
// 仅当ageEnd不为空时才添加小于等于条件
if (ageEnd != null) {
queryWrapper.le("age", ageEnd);
}
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
优化思路(使用 condition 参数)
MyBatis-Plus 的条件方法提供了带condition参数的重载方法,可简化代码:
@Test
public void testCondition2() {
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// condition为true时才添加该条件
queryWrapper.like(StringUtils.isNotBlank(username), "name", username)
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
五、LambdaQueryWrapper(推荐)
LambdaQueryWrapper 使用 Lambda 表达式指定字段,避免字符串硬编码,能在编译期发现字段错误,更安全:
@Test
public void testLambdaQueryWrapper() {
// 定义可能为null的查询条件
String username = "a";
Integer ageBegin = 10;
Integer ageEnd = 24;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
// 条件判断+Lambda表达式
queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
六、LambdaUpdateWrapper(推荐)
LambdaUpdateWrapper 同样使用 Lambda 表达式,适合构建更新条件:
@Test
public void testLambdaUpdateWrapper() {
// 将名字中包含"a",且年龄小于24或邮箱为空的用户,年龄改为18,邮箱改为user@qcby.com
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.like(User::getName, "a")
.and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail)) // 嵌套条件
.set(User::getAge, 18)
.set(User::getEmail, "user@qcby.com");
int result = userMapper.update(null, updateWrapper);
System.out.println("受影响的行数:" + result);
}
七、Wrapper 使用总结
Wrapper 类型 | 特点 | 适用场景 |
QueryWrapper | 字符串指定字段 | 简单查询,字段名不易出错的场景 |
UpdateWrapper | 支持 SET 语句构建 | 复杂更新操作 |
LambdaQueryWrapper | Lambda 表达式指定字段,编译期检查 | 复杂查询,追求类型安全 |
LambdaUpdateWrapper | Lambda 表达式指定字段,支持复杂条件 | 复杂更新,追求类型安全 |