Appearance
条件构造器(Wrapper)
条件构造器是 MyBatis-Plus 最强大的特性之一,让你用 Lambda 表达式构建 SQL WHERE 条件,类型安全,告别字符串硬编码。
一、四种 Wrapper 对比
| Wrapper | 用途 | 字段引用方式 | 推荐度 |
|---|---|---|---|
| QueryWrapper | 条件查询 | 字符串 "name" | 一般 |
| UpdateWrapper | 条件更新 | 字符串 "name" | 一般 |
| LambdaQueryWrapper | 条件查询 | Lambda User::getName | 推荐 |
| LambdaUpdateWrapper | 条件更新 | Lambda User::getAge | 推荐 |
java
// 字符串方式(不推荐:字段名拼错编译期发现不了)
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("name", "张三"); // "name" 写错了编译不报错
// Lambda 方式(推荐:字段名由编译器检查)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.eq(User::getName, "张三"); // 写错了编译就报错二、LambdaQueryWrapper 条件方法
2.1 比较条件
java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 等于 =
wrapper.eq(User::getName, "张三");
// 不等于
wrapper.ne(User::getAge, 25);
// 大于 >
wrapper.gt(User::getAge, 20);
// 大于等于 >=
wrapper.ge(User::getAge, 18);
// 小于 <
wrapper.lt(User::getAge, 60);
// 小于等于 <=
wrapper.le(User::getAge, 60);2.2 模糊查询
java
// LIKE '%张%'
wrapper.like(User::getName, "张");
// LIKE '%张'(左模糊)
wrapper.likeLeft(User::getName, "张");
// LIKE '张%'(右模糊)
wrapper.likeRight(User::getName, "张");2.3 范围查询
java
// BETWEEN 值1 AND 值2
wrapper.between(User::getAge, 20, 30);
// NOT BETWEEN
wrapper.notBetween(User::getAge, 20, 30);
// IN (1, 2, 3)
wrapper.in(User::getId, Arrays.asList(1L, 2L, 3L));
// NOT IN
wrapper.notIn(User::getId, Arrays.asList(1L, 2L, 3L));2.4 空值判断
java
// IS NULL
wrapper.isNull(User::getEmail);
// IS NOT NULL
wrapper.isNotNull(User::getEmail);2.5 分组与排序
java
// GROUP BY
wrapper.groupBy(User::getAge);
// HAVING
wrapper.having("COUNT(*) > {0}", 5);
// ORDER BY ASC
wrapper.orderByAsc(User::getAge);
// ORDER BY DESC
wrapper.orderByDesc(User::getCreateTime);
// 多字段排序
wrapper.orderByAsc(User::getAge)
.orderByDesc(User::getCreateTime);2.6 逻辑组合
java
// AND 嵌套(默认就是 AND)
wrapper.eq(User::getName, "张三")
.eq(User::getAge, 25);
// OR
wrapper.eq(User::getName, "张三")
.or()
.eq(User::getName, "李四");
// WHERE name = '张三' OR name = '李四'
// AND 嵌套(括号)
wrapper.eq(User::getName, "张三")
.and(w -> w.eq(User::getAge, 25).or().eq(User::getAge, 30));
// WHERE name = '张三' AND (age = 25 OR age = 30)
// OR 嵌套
wrapper.eq(User::getName, "张三")
.or(w -> w.eq(User::getAge, 25).eq(User::getEmail, "test@test.com"));
// WHERE name = '张三' OR (age = 25 AND email = 'test@test.com')2.7 条件 SQL
java
// 直接拼接 SQL(慎用)
wrapper.apply("DATE_FORMAT(create_time, '%Y-%m-%d') = {0}", "2024-01-01");
// 自定义 SQL 片段
wrapper.last("LIMIT 1"); // 拼接到最后
wrapper.exists("SELECT 1 FROM order WHERE user_id = user.id"); // EXISTS 子查询三、实战场景
3.1 动态条件查询
java
public List<User> searchUsers(String name, Integer minAge, Integer maxAge, String email) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 只有参数不为空时才添加条件
wrapper.like(StringUtils.hasText(name), User::getName, name)
.ge(minAge != null, User::getAge, minAge)
.le(maxAge != null, User::getAge, maxAge)
.eq(StringUtils.hasText(email), User::getEmail, email)
.orderByDesc(User::getCreateTime);
return userMapper.selectList(wrapper);
}关键: 第一个参数
boolean condition控制是否添加该条件,为false时跳过。
3.2 复杂条件查询
java
// 查询:name 包含"张" 且 (age < 20 或 age > 60) 且 email 不为空
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getName, "张")
.and(w -> w.lt(User::getAge, 20).or().gt(User::getAge, 60))
.isNotNull(User::getEmail);
List<User> users = userMapper.selectList(wrapper);
// SQL: SELECT * FROM user
// WHERE name LIKE '%张%'
// AND (age < 20 OR age > 60)
// AND email IS NOT NULL3.3 只查部分字段
java
// 只查 id 和 name
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName)
.eq(User::getAge, 25);
List<User> users = userMapper.selectList(wrapper);
// SQL: SELECT id, name FROM user WHERE age = 253.4 排除某字段
java
// 查除了 email 以外的所有字段
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User.class, info -> !info.getColumn().equals("email"));四、LambdaUpdateWrapper
java
// 修改 name 为"张三"的用户的 age 为 30
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(User::getAge, 30)
.set(User::getEmail, "new@test.com")
.eq(User::getName, "张三");
userMapper.update(null, wrapper);
// UPDATE user SET age = 30, email = 'new@test.com' WHERE name = '张三'java
// 根据条件动态更新
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getName, "张三");
if (newAge != null) {
wrapper.set(User::getAge, newAge);
}
if (newEmail != null) {
wrapper.set(User::getEmail, newEmail);
}
userMapper.update(null, wrapper);五、常用条件速查表
| 方法 | 含义 | SQL 等价 |
|---|---|---|
| eq | 等于 | = |
| ne | 不等于 | <> |
| gt | 大于 | > |
| ge | 大于等于 | >= |
| lt | 小于 | < |
| le | 小于等于 | <= |
| like | 模糊 | LIKE '%值%' |
| likeLeft | 左模糊 | LIKE '%值' |
| likeRight | 右模糊 | LIKE '值%' |
| between | 区间 | BETWEEN 值1 AND 值2 |
| in | 包含 | IN (值1, 值2) |
| isNull | 为空 | IS NULL |
| isNotNull | 不为空 | IS NOT NULL |
| orderByAsc | 升序 | ORDER BY ASC |
| orderByDesc | 降序 | ORDER BY DESC |
| groupBy | 分组 | GROUP BY |
| having | 分组过滤 | HAVING |
| and | 逻辑与 | AND |
| or | 逻辑或 | OR |
六、速记总结
条件构造器选择:
LambdaQueryWrapper → 查询用
LambdaUpdateWrapper → 更新用
动态条件写法:
wrapper.eq(condition, 字段, 值)
第一个参数 = false → 跳过该条件
嵌套逻辑:
.and(w -> w.条件1.or().条件2) → (条件1 OR 条件2)
.or(w -> w.条件1.条件2) → OR (条件1 AND 条件2)
速记口诀:
Lambda 写条件,类型安全编译检,
eq 等于 ne 不等,gt 大于 lt 小于,
like 模糊 between 区间,in 包含 null 判空,
and 嵌套 or 嵌套,condition 做前置。七、面试要点
| 问题 | 答案要点 |
|---|---|
| 为什么推荐 Lambda 方式? | 类型安全,字段名编译期检查,防止拼写错误 |
| 怎么实现动态条件? | 第一个参数 boolean condition 控制 |
| 如何嵌套 OR 条件? | .and(w -> w.xxx.or().xxx) |
