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. 自检

  1. QueryWrapper 与 LambdaQueryWrapper 的关键差别?
  2. apply 的两种写法安全性差异?
  3. 怎么让"参数为空时自动跳过条件"?
  4. 为什么 or 必须配括号?
  5. 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/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。