MyBatis-Plus03:条件构造器
一、条件构造器
MyBatis-Plus(MP)的核心优势之一,就是通过 Wrapper 体系(尤其是 QueryWrapper 和 UpdateWrapper)提供了强大、灵活且类型安全的动态 SQL 构建能力,特别擅长处理复杂的 WHERE 条件。

1-1、AbstractWrapper

1、QueryWrapper && UpdateWrapper

QueryWrapper 在where条件的基础上,可以控制多加了select 可选的查询字段。
默认是select *
(1)QueryWrapper 示例:


(2)updateWrapper示例:

UpdateWrapper第一个参数传null是因为你不提供实体对象;如果你传了实体,MP 会把实体中非空字段也加入 SET,可能造成意料之外的覆盖。
⚠️ 注意事项
如果你有实体对象,并且想更新它的某些字段 + 按主键更新,也可以用:
User user = new User();
user.setId(1001);
user.setNickname("新昵称");
userMapper.updateById(user); // 更简洁
这种情况不需要 UpdateWrapper。
小结:
| 场景 | 推荐方式 |
|---|---|
| 按主键更新几个字段 | updateById(entity) |
| 按非主键条件更新 | update(null, updateWrapper) |
| 动态条件/字段更新 | UpdateWrapper 或 LambdaUpdateWrapper |
2、AbstractLambdaWrapper
以上的queryWrapper 和 updateWrapper 字段名都是写死的,硬编码。

二、小结

三、QueryWrapper VS UpdateWrapper
3-1、一句话区分
| Wrapper | 用途 | 核心能力 |
|---|---|---|
QueryWrapper |
查询、删除 | 只构造 WHERE 条件 |
UpdateWrapper |
更新 | 构造 WHERE 条件 + SET 更新内容 |
3-2、继承关系
AbstractWrapper ← 所有 Wrapper 的基类(构造 WHERE)
├── QueryWrapper ← 只负责 WHERE
├── UpdateWrapper ← 负责 WHERE + SET
└── LambdaQueryWrapper / LambdaUpdateWrapper ← 各自对应的 Lambda 版本
UpdateWrapper 比 QueryWrapper 多了一个 set() 方法,用来指定要更新的字段和值。
3-3、代码对比:同一个业务场景
场景:把"年龄大于 30 且状态为禁用"的用户,状态改为启用。
❌ 错误:用 QueryWrapper 做更新
// QueryWrapper 只能构造 WHERE,没法指定 SET 内容!
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 30).eq("status", 0);
// update() 方法需要传入一个实体对象作为 SET 内容
User user = new User();
user.setStatus(1); // 要更新的字段值放在实体里
userMapper.update(user, queryWrapper);
缺点:
-
实体
user中其他字段如果为null,配合not_null策略会被忽略,但你得new一个对象 -
逻辑上"条件和更新内容"分离,不够直观
✅ 正确:用 UpdateWrapper 做更新
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
// WHERE 条件:年龄 > 30 且 状态 = 0
updateWrapper.gt("age", 30).eq("status", 0);
// SET 内容:直接在这里指定!
updateWrapper.set("status", 1);
// 还可以同时更新多个字段
updateWrapper.set("update_time", new Date());
userMapper.update(null, updateWrapper);
优点:
-
条件和更新内容写在一起,一目了然
-
第一个参数传
null,完全不需要 new 实体对象 -
可以更新为
null(set("phone", null)),不受实体 null 策略影响
3-4、什么时候用哪个?(决策树)
你要做什么操作?
│
├─→ 查询(SELECT)─────────────────→ QueryWrapper / LambdaQueryWrapper
│ 例:list(wrapper)、getOne(wrapper)、count(wrapper)
│
├─→ 删除(DELETE)─────────────────→ QueryWrapper / LambdaQueryWrapper
│ 例:remove(wrapper)
│ (删除只需要条件,不需要 SET)
│
└─→ 更新(UPDATE)─────────────────→ UpdateWrapper / LambdaUpdateWrapper
例:update(null, wrapper)
(更新既需要 WHERE 条件,又需要 SET 内容)
3-5、Lambda 版本(推荐实际使用)
上面用的是字符串硬编码列名,容易写错。实际开发强烈推荐 Lambda 版本:
LambdaQueryWrapper —— 查询/删除
// 查询:名字包含"张"且状态启用的用户
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.like(User::getUsername, "张")
.eq(User::getStatus, 1);
List<User> list = userMapper.selectList(lqw);
LambdaUpdateWrapper —— 更新
// 更新:id=1 的用户,只改邮箱和更新时间
LambdaUpdateWrapper<User> luw = new LambdaUpdateWrapper<>();
luw.eq(User::getId, 1L)
.set(User::getEmail, "new@qq.com")
.set(User::getUpdateTime, new Date());
userMapper.update(null, luw);
Lambda 的好处: User::getUsername 是编译期检查的,列名写错直接编译报错,不会等到运行时才暴露。
3-6、一个完整的实战对比
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// ========== 查询:用 QueryWrapper ==========
public List<User> getActiveUsersByAge(Integer minAge) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(User::getAge, minAge) // WHERE age >= ?
.eq(User::getStatus, 1); // AND status = 1
return userMapper.selectList(wrapper);
}
// ========== 删除:用 QueryWrapper ==========
public boolean deleteInactiveUsers() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, 0) // WHERE status = 0
.lt(User::getCreateTime,
LocalDateTime.now().minusYears(1)); // AND create_time < '一年前'
return userMapper.delete(wrapper) > 0;
}
// ========== 更新:用 UpdateWrapper ==========
public boolean banUsersByAge(Integer maxAge) {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.le(User::getAge, maxAge) // WHERE age <= ?
.eq(User::getStatus, 1) // AND status = 1
.set(User::getStatus, 0) // SET status = 0
.set(User::getUpdateTime,
LocalDateTime.now()); // SET update_time = now()
return userMapper.update(null, wrapper) > 0;
}
}
3-7、容易踩的坑
| 坑 | 说明 |
|---|---|
| UpdateWrapper 做查询 | 语法上可行(因为继承了 AbstractWrapper),但语义不对,别这么干 |
| QueryWrapper 做更新但没传实体 | update(null, queryWrapper) → SET 子句为空,SQL 报错 |
| UpdateWrapper 传了实体又用了 set() | 两者会合并,实体和 set() 都会进 SET 子句,注意别重复 |
忘记 update(null, wrapper) 第一个参数 |
用 UpdateWrapper 时第一个参数固定传 null |
3-8、速记口诀
查删用 Query,更新用 Update。 Query 只管 WHERE,Update 还能 SET。
更多推荐




所有评论(0)