核心问题
SQL 中 AND 优先级高于 OR。MyBatis-Plus 的 Wrapper 链式调用如果不显式分组,生成的 SQL 括号位置可能与预期不符,导致筛选条件失效。
场景一:OR 与后续 AND 条件混用
错误写法
// 意图:查 (我的房源 或 团队房源) 且满足后续筛选条件
wrapper.in(TbHouse::getUserId, ids)
.or()
.eq(TbHouse::getTeamId, params.getTeamId());
// 后续追加
wrapper.eq(TbHouse::getRentSale, params.getRentSale());
wrapper.eq(TbHouse::getStatus, params.getStatus());
生成的 SQL(错误)
WHERE user_id IN (?,?,?)
OR team_id = ? AND rent_sale = ? AND status = ?
由于 AND > OR,实际逻辑等价于:
WHERE user_id IN (?,?,?)
OR (team_id = ? AND rent_sale = ? AND status = ?)
后果: user_id IN 分支完全绕过了 rent_sale 和 status 筛选,导致查询结果包含不该出现的数据。
正确写法
wrapper.and(w -> w.in(TbHouse::getUserId, ids)
.or()
.eq(TbHouse::getTeamId, params.getTeamId()));
// 后续条件正常追加
wrapper.eq(TbHouse::getRentSale, params.getRentSale());
wrapper.eq(TbHouse::getStatus, params.getStatus());
生成的 SQL(正确)
WHERE (user_id IN (?,?,?) OR team_id = ?)
AND rent_sale = ?
AND status = ?
记忆口诀
只要链式调用了 .or(),且后续还需要追加 AND 条件,就必须用 .and() 包裹 OR 组。
场景二:多字段模糊搜索(有意的 OR 组)
这种场景 .and() 本身就是正确的用法:
// 多个字段模糊匹配,任一命中即可
wrapper.and(w -> w.like(TbHouse::getName, keyword)
.or()
.like(TbHouse::getDoorplate, keyword)
.or()
.like(TbHouse::getOwnerName, keyword));
// 这里 and() 内的 OR 不受外部 AND 条件影响,正确
wrapper.eq(TbHouse::getStatus, 1); // 额外筛选
生成:
WHERE (name LIKE '%kw%' OR doorplate LIKE '%kw%' OR owner_name LIKE '%kw%')
AND status = 1
.and()的本质
.and(Consumer<Wrapper> consumer) 创建一个用括号包裹的子条件组,以 AND 方式连接到外层:
| 写法 | SQL |
|---|---|
wrapper.eq(A, 1).eq(B, 2) |
WHERE a=1 AND b=2 |
wrapper.eq(A, 1).or().eq(B, 2) |
WHERE a=1 OR b=2 |
wrapper.and(w -> w.eq(A, 1).or().eq(B, 2)) |
WHERE (a=1 OR b=2) |
wrapper.and(w -> w.eq(A, 1).or().eq(B, 2)).eq(C, 3) |
WHERE (a=1 OR b=2) AND c=3 |
注意区分 and() 与 and(Consumer):
and()— 无参,只是一个 AND 连接符,不创建括号and(Consumer)— 有参,创建括号子组
排查方法
当遇到"加了筛选条件但结果不对"时:
- 开启 MyBatis-Plus SQL 日志:
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl - 观察实际执行的 SQL 括号位置
- 检查代码中
.or()是否被.and()正确包裹
