目录
[7.4 QueryWrapper](#7.4 QueryWrapper)
[7.5 condition](#7.5 condition)
[7.6 LambdaQueryWrapper](#7.6 LambdaQueryWrapper)
[7.7 LambdaUpdateWrapper](#7.7 LambdaUpdateWrapper)
7.4 QueryWrapper
-
组装查询条件
@Test
public void test01(){
//查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "a")
.between("age", 20, 30)
.isNotNull("email");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
注:条件构造器默认用AND连接多个条件,除非显式调用or()切换逻辑运算符。

-
组装排序条件
@Test
public void test02(){
//按年龄降序查询用户,如果年龄相同则按id升序排列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.orderByDesc("age")
.orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

-
组装删除条件
@Test
public void test03(){
//删除email为空的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
//条件构造器也可以构建删除语句的条件
int result = userMapper.delete(queryWrapper);
System.out.println("受影响的行数:" + result);
}

- 条件的优先级
-
测试一:
@Test
public void test04() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
queryWrapper
.like("name", "a")// 条件1
.gt("age", 20)// 条件2(默认AND连接条件1)
.or() // 切换为OR连接
.isNull("email");// 条件3
User user = new User();
user.setAge(18);
user.setEmail("user@qcby.com");
int result = userMapper.update(user, queryWrapper);
System.out.println("受影响的行数:" + result);
}
注:
test04 中,or() 是直接拼接,条件分组为 (A AND B) OR C;
条件构造器默认用AND连接多个条件,除非显式调用or()切换逻辑运算符。

-
测试二:
@Test
public void test041() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
//lambda表达式内的逻辑优先运算
queryWrapper
.like("name", "a")// 条件1
.and(i -> i.gt("age", 20)// 条件1之后用AND连接"lambda内的分组条件",条件2
.or()// 条件2和3用OR连接
.isNull("email"));// 条件3
User user = new User();
user.setAge(18);
user.setEmail("user@qcby.com");
int result = userMapper.update(user, queryWrapper);
System.out.println("受影响的行数:" + result);
}
注:
test041 中,and( lambda ) 会给 lambda 内的条件加括号,分组为 A AND (B OR C)。
MyBatis-Plus 的条件构造器不会给每个条件单独加小括号,只有通过and(lambda)/or(lambda),如and(i->...),显式分组时,才会给 lambda 内的条件加括号。

-
组装select子句
@Test
public void test05() {
//查询用户信息的name和age字段
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name", "age");
//selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值 为null
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}

-
实现子查询
@Test
public void test06() {
//查询id小于等于3的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "select id from tx_user where id <= 3");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}

- 注意事项
- QueryWrapper:当泛型是自定义的 VO/DTO 时,QueryWrapper 不会校验字段是否存在于数据库表中。如果泛型是数据库实体类(如 QueryWrapper)时,它会非常 "严格"。它会去检查你写的列名(如 "user_name")是否真的存在于 person 表中(通过实体类的 @TableField 注解)。如果你写了一个它不认识的名字(如 "p.community_id"),它可能会报错。
- 直接使用别名:如果泛型是自定义的VO/DTO,你可以在 eq(), like() 等方法中,直接使用你在自定义 SQL 中定义的表别名(如 "p.community_id")。${ew.customSqlSegment}:它会忠实地将 QueryWrapper 中构建的条件(包括别名)拼接到最终的 SQL 语句中。
7.5 condition
在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因 此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若 没有选择则一定不能组装,以免影响SQL执行的结果。
解决这个问题有两种方法,第一个是使用if判断,第二个是使用condition参数。
-
使用if判断
@Test
public void test08() {
//定义查询条件,有可能为null(用户未输入或未选择)
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace) 构成
if(StringUtils.isNotBlank(username)){
queryWrapper.like("name","a");
}
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);
}
注:第9行代码要导入的包是import com.baomidou.mybatisplus.core.toolkit.StringUtils;。

-
使用带condition参数
上面的实现方案没有问题,但是代码比较复杂,我们可以使用带condition参数的重载方法构建查 询条件,简化代码的编写@Test
public void test08UseCondition() {
//定义查询条件,有可能为null(用户未输入或未选择)
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace) 构成
queryWrapper
.like(StringUtils.isNotBlank(username), "name", "a")
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

7.6 LambdaQueryWrapper
@Test
public void test09() {
//定义查询条件,有可能为null(用户未输入)
String username = "a";
Integer ageBegin = 10;
Integer ageEnd = 24;
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> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
注:
User::getName 是 Java 8 引入的方法引用(属于 Lambda 表达式的简化写法),它指向 User 类的 getName() 方法。但是在在 MyBatis-Plus 中,LambdaQueryWrapper 接收的 User::getName 并不是真的要执行这个方法,而是通过反射"提取" 这个方法对应的字段名:
- 你传入 User::getName,它本质是一个 Function 类型的 Lambda(表示 "从 User 对象中获取 name 属性的函数");
- MyBatis-Plus 通过解析这个 Lambda 表达式,获取到对应的方法名 getName();
- 按照 Java Bean 规范,从方法名反推出字段名 name;
- 最终拼接 SQL 时,用推断出的 name 代替字符串,避免手写错误。
上面的反射主要体现在下面几个方面中: - 解析 Lambda 表达式获取方法信息:User::getName 作为 Lambda 表达式传入后,MyBatis-Plus 会通过 java.lang.invoke.SerializedLambda(Lambda 序列化工具类)获取该方法的名称(如getName)、所属类(User.class)等信息。这一步需要通过反射访问 Lambda 表达式的私有属性(比如 SerializedLambda 的构造器是私有的,需要反射调用)。
- 从方法名推导字段名:拿到 getName 后,按照 Java Bean 规范(getXxx → xxx,isXxx → xxx),截取并转换为字段名 name。如果需要验证字段是否真的存在于 User 类中,还会通过反射调用 User.class.getDeclaredField("name") 检查字段合法性。
- 拼接 SQL 时的字段映射:最终拼接 SQL(如 WHERE name LIKE ?)时,框架需要确认 User 类的 name 字段是否有别名(比如 @TableField("user_name")),这一步也需要通过反射读取字段的注解信息。
使用Lambda 表达式的好处: - 用字符串 "name" 表示字段名有个致命问题:编译期无法检查错误。比如你手滑写成 "nme",编译器不会报错,但运行时会因为字段不存在抛出异常。
- 而 User::getName 是通过类的方法引用关联字段,编译器会直接检查:User 类有没有 getName() 方法?如果写错(比如 User::getNme),编译器直接标红,提前规避错误。

7.7 LambdaUpdateWrapper
@Test
public void test10() {
//组装set子句
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper
.set(User::getAge, 18)
.set(User::getEmail, "user@qcby.com")
.like(User::getName, "a")
.and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail)); //lambda 表达式内的逻辑优先运算
User user = new User();
int result = userMapper.update(user, updateWrapper);
System.out.println("受影响的行数:" + result);
}
