780 字
约 2 分钟
6
S08-B05 · Wrapper 条件构造器
适用读者:用字符串拼
where拼到崩溃的人。
前置:S08-B04。
实测环境:MyBatis-Plus 3.5.7 / H2(2026-11-05)。
覆盖旧文:1183(184) 1184(23) = 207 点。
上一篇:S08-B04 · MyBatis-Plus 基础:CRUD、注解、逻辑删除
下一篇:S08-J01 · 分页。
1. 一句话结论
Wrapper 是"用代码构造 WHERE 的 DSL":它解决条件组合与空值处理,但不解决手写 SQL 片段带来的注入风险**——apply() 就是那个缺口。**
2. 实测:条件如何被拼出来
m.selectList(new QueryWrapper<User>().ge("age", 20).like("user_name", "a"));
实测 SQL:
SELECT id,user_name,age,deleted,version FROM sys_user
WHERE deleted=0 AND (age >= ? AND user_name LIKE ?)
==> Parameters: 20(Integer), %a%(String)
两个细节:
| 细节 | 含义 |
|---|---|
deleted=0 在最外层 |
逻辑删除自动追加 |
| 条件被括号包住 | 与自动条件不会因为 or 而被绕过 |
3. 三种 Wrapper
| 类型 | 写法 | 特点 |
|---|---|---|
QueryWrapper |
字符串列名 .eq("user_name", v) |
易拼错列名 |
LambdaQueryWrapper |
.eq(User::getUserName, v) |
类型安全(推荐) |
UpdateWrapper |
用于 update 的 set/where | — |
判据:默认用 LambdaQueryWrapper——列名写错在编译期就能发现。
4. 安全边界:apply 与 ${} 同源
wrapper.apply("age > {0}", 18); // ✅ 参数化(占位)
wrapper.apply("age > " + age); // ❌ 拼接(注入)
| 写法 | 安全性 |
|---|---|
eq/ge/like/in 等 |
✅ 参数化 |
apply("sql {0}", arg) |
✅ 占位符 |
apply("sql " + arg) |
❌ 等同于 ${}(S08-B02) |
last("limit 10") |
⚠️ 拼接(只放常量) |
这是本篇最重要的一条:Wrapper 不是"安全"的同义词,它只是把常见操作参数化了。
5. 条件组合的四个技巧
| 需求 | 写法 |
|---|---|
| 条件为空时跳过 | eq(StringUtils.isNotBlank(name), "user_name", name)(第一个参数是 boolean) |
| 嵌套 or | .and(w -> w.eq(...).or().eq(...)) |
in 空集合保护 |
集合为空时不要调用 in(会生成 in () 语法错) |
| 排序 | .orderByDesc(User::getId) |
"第一个参数是 boolean"这个重载是最实用的特性——省掉大量 if 判断。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "用了 Wrapper 就安全" | apply 拼接仍可注入 |
| "字符串列名也能类型安全" | 只有 Lambda 版能 |
"in() 空集合没事" |
生成 in () 报语法错 |
| "Wrapper 能表达任意 SQL" | 复杂联表仍要 XML |
| "条件顺序无所谓" | or 不加括号会改变语义 |
7. 自检
QueryWrapper与LambdaQueryWrapper的关键差别?apply的两种写法安全性差异?- 怎么让"参数为空时自动跳过条件"?
- 为什么
or必须配括号? in()传空集合会怎样?
8. 下一篇
S08-J01 · 分页:PageHelper vs MP 分页插件
Wrapper 讲完,进阶层开始:分页插件怎么把 LIMIT 塞进 SQL,以及深翻为什么慢。
本篇属于系列《S08 · MyBatis 持久层》。旧文来源:A-1183/1184。Wrapper 生成的 SQL 为 MP 3.5.7 实测。
S08-B05 · Wrapper 条件构造器
https://www.clxhxhhr.top/posts/5286/ 评论
0 条
还没有评论,先写一条吧。