MyBatis-Plus 条件构造器详解目录1 Wrapper 体系概览2 QueryWrapper2.1 组装查询条件2.2 组装排序条件2.3 组装删除条件2.4 条件的优先级2.5 组装 select 子句2.6 实现子查询3 UpdateWrapper4 Condition —— 动态组装条件4.1 传统方式if 判断4.2 简化方式condition 参数5 LambdaQueryWrapper6 LambdaUpdateWrapper1 Wrapper 体系概览MyBatis-Plus 提供了一套条件构造器Wrapper用于构建 SQL 中的 WHERE 条件避免手写 SQL 字符串。其类层次结构如下类名说明Wrapper条件构造抽象类最顶端父类AbstractWrapper查询条件封装生成 SQL 的 WHERE 条件QueryWrapper查询/删除条件封装UpdateWrapper更新条件封装可同时设置 SET 子句和 WHERE 条件AbstractLambdaWrapperLambda 语法的抽象父类LambdaQueryWrapperLambda 语法的查询条件封装LambdaUpdateWrapperLambda 语法的更新条件封装常用的条件方法速查方法对应 SQL示例eq ?.eq(age, 20)ne ?.ne(age, 20)gt ?.gt(age, 20)ge ?.ge(age, 20)lt ?.lt(age, 20)le ?.le(age, 20)likeLIKE %?%.like(name, a)betweenBETWEEN ? AND ?.between(age, 20, 30)isNullIS NULL.isNull(email)isNotNullIS NOT NULL.isNotNull(email)inIN (?, ?).in(id, 1, 2, 3)inSqlIN (子查询).inSql(id, select id from ...)orderByAscORDER BY ? ASC.orderByAsc(id)orderByDescORDER BY ? DESC.orderByDesc(age)orOR.or()andAND (嵌套).and(i - i.gt(...).or()...)select指定查询字段.select(name, age)setSET 字段值.set(age, 18)2 QueryWrapperQueryWrapper是最常用的条件构造器用于构建 SELECT、DELETE 语句的 WHERE 条件。2.1 组装查询条件查询用户名包含a、年龄在 20 到 30 之间、且邮箱不为 null 的用户Testpublicvoidtest01(){// SELECT id,username AS name,age,email,is_deleted FROM t_user// WHERE is_deleted0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.like(username,a).between(age,20,30).isNotNull(email);ListUserlistuserMapper.selectList(queryWrapper);list.forEach(System.out::println);}多个条件通过链式调用拼接默认使用AND连接。2.2 组装排序条件按年龄降序排列年龄相同时按 id 升序排列Testpublicvoidtest02(){// SELECT id,username AS name,age,email,is_deleted FROM t_user// WHERE is_deleted0 ORDER BY age DESC, id ASCQueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.orderByDesc(age).orderByAsc(id);ListUserusersuserMapper.selectList(queryWrapper);users.forEach(System.out::println);}2.3 组装删除条件条件构造器不仅能用于查询也可以用于构建删除语句的条件Testpublicvoidtest03(){// DELETE FROM t_user WHERE (email IS NULL)QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.isNull(email);intresultuserMapper.delete(queryWrapper);System.out.println(受影响的行数result);}2.4 条件的优先级使用or()方法可以将默认的 AND 连接切换为 ORTestpublicvoidtest04(){// 将用户名包含a并且年龄大于20或邮箱为null的用户信息修改// UPDATE t_user SET age?, email? WHERE (username LIKE ? AND age ? OR email IS NULL)QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.like(username,a).gt(age,20).or().isNull(email);UserusernewUser();user.setAge(38);user.setEmail(kobeqq.com);intresultuserMapper.update(user,queryWrapper);System.out.println(受影响的行数result);}如果需要改变优先级加括号可以使用and()方法传入 Lambda 表达式Lambda 内部的条件会被括号包裹Testpublicvoidtest04Priority(){// 将用户名包含a并且年龄大于20或邮箱为null的用户信息修改// UPDATE t_user SET age?, email? WHERE (username LIKE ? AND (age ? OR email IS NULL))QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.like(username,a).and(i-i.gt(age,20).or().isNull(email));UserusernewUser();user.setAge(18);user.setEmail(oscar163.com);intresultuserMapper.update(user,queryWrapper);System.out.println(受影响的行数result);}关键区别.or()改变紧随其后一个条件的连接方式为 OR.and(i - ...)Lambda 内部的条件用括号包裹实现优先级提升2.5 组装 select 子句默认查询会返回所有字段。使用select()方法可以指定只查询部分字段Testpublicvoidtest05(){// SELECT username, age FROM t_userQueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.select(username,age);ListMapString,ObjectmapsuserMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}这里使用selectMaps()而非selectList()返回MapString, Object集合避免未查询的字段在实体对象中显示为 null。2.6 实现子查询使用inSql()方法可以构造 IN 子查询Testpublicvoidtest06(){// SELECT id,username AS name,age,email,is_deleted FROM t_user// WHERE (id IN (select id from t_user where id 3))QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.inSql(id,select id from t_user where id 3);ListUserlistuserMapper.selectList(queryWrapper);list.forEach(System.out::println);}inSql()的第二个参数是原生 SQL 字符串适合需要嵌套子查询的场景。3 UpdateWrapperUpdateWrapper可以同时设置 WHERE 条件和 SET 子句不需要依赖实体对象来传递更新字段Testpublicvoidtest07(){// UPDATE t_user SET age?, email? WHERE (username LIKE ? AND (age ? OR email IS NULL))UpdateWrapperUserupdateWrappernewUpdateWrapper();updateWrapper.set(age,18).set(email,userqq.com).like(username,a).and(i-i.gt(age,20).or().isNull(email));intresultuserMapper.update(null,updateWrapper);System.out.println(result);}QueryWrapper vs UpdateWrapper 在更新场景下的区别对比项QueryWrapperUpdateWrapper更新字段来源通过实体对象的非 null 属性通过.set()方法直接指定update()第一个参数必须传入实体对象可以传 null适用场景更新字段由实体对象决定需要精确控制更新字段或需要将字段设为 null4 Condition —— 动态组装条件实际开发中查询条件往往来自用户输入是可选的。如果用户没有输入某个条件就不应该将其组装到 SQL 中。4.1 传统方式if 判断Testpublicvoidtest08(){Stringusernamenull;IntegerageBegin10;IntegerageEnd24;QueryWrapperUserqueryWrappernewQueryWrapper();if(StringUtils.isNotBlank(username)){queryWrapper.like(username,a);}if(ageBegin!null){queryWrapper.ge(age,ageBegin);}if(ageEnd!null){queryWrapper.le(age,ageEnd);}// username 为 null不参与条件组装// SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age ? AND age ?)ListUserusersuserMapper.selectList(queryWrapper);users.forEach(System.out::println);}这种方式功能正确但 if 判断较多代码比较冗长。4.2 简化方式condition 参数MyBatis-Plus 的条件方法都提供了带condition参数的重载版本。当condition为true时才组装该条件为false时自动跳过Testpublicvoidtest08UseCondition(){Stringusernamenull;IntegerageBegin10;IntegerageEnd24;QueryWrapperUserqueryWrappernewQueryWrapper();queryWrapper.like(StringUtils.isNotBlank(username),username,a).ge(ageBegin!null,age,ageBegin).le(ageEnd!null,age,ageEnd);// SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age ? AND age ?)ListUserusersuserMapper.selectList(queryWrapper);users.forEach(System.out::println);}效果与 if 判断完全一致但代码更简洁。方法签名中第一个参数即为condition例如like(boolean condition, String column, Object val)。5 LambdaQueryWrapperQueryWrapper中的字段名使用字符串硬编码如果字段名拼写错误编译期不会报错运行时才会发现。LambdaQueryWrapper通过方法引用代替字符串将字段名的校验提前到编译期Testpublicvoidtest09(){Stringusernamea;IntegerageBegin10;IntegerageEnd24;LambdaQueryWrapperUserqueryWrappernewLambdaQueryWrapper();queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username).ge(ageBegin!null,User::getAge,ageBegin).le(ageEnd!null,User::getAge,ageEnd);ListUserusersuserMapper.selectList(queryWrapper);users.forEach(System.out::println);}QueryWrapper vs LambdaQueryWrapper对比项QueryWrapperLambdaQueryWrapper字段引用方式字符串username方法引用User::getName编译期检查❌ 字段名拼错不会报编译错误✅ 方法引用不存在时编译报错重构安全性❌ 重命名字段后需手动修改字符串✅ IDE 自动同步推荐程度简单场景可用推荐使用6 LambdaUpdateWrapper与LambdaQueryWrapper类似LambdaUpdateWrapper用方法引用代替字符串来构建更新语句Testpublicvoidtest10(){LambdaUpdateWrapperUserupdateWrappernewLambdaUpdateWrapper();updateWrapper.set(User::getAge,18).set(User::getEmail,useratguigu.com).like(User::getName,a).and(i-i.lt(User::getAge,24).or().isNull(User::getEmail));UserusernewUser();intresultuserMapper.update(user,updateWrapper);System.out.println(受影响的行数result);}实际开发中推荐优先使用 Lambda 系列的条件构造器LambdaQueryWrapper和LambdaUpdateWrapper编译期即可发现字段引用错误减少线上问题。