[toc]
| 单词 | 词性 | 音标 | 含义 |
|---|---|---|---|
| Lambda | n. | /ˈlæmdə/ | 希腊字母 λ(Java 8 引入的函数式写法,LambdaQueryWrapper 用 Employee::getEmpName 这种形式引用属性) |
| Reference | n. | /ˈrefrəns/ | 引用(Employee::getEmpName 是方法引用,指向实体类的 getter 方法) |
| And / Or | conj. | /ænd/ /ɔː(r)/ | 与 / 或(条件之间用 and、or 组合,形成嵌套逻辑) |
Lecture06-条件构造器[二]-LambdaQueryWrapper
一、QueryWrapper 的缺点
上一章 QueryWrapper 里,列名是手写字符串:
wrapper.eq("dept_id", 1)
.like("emp_name", "张");
它的两个痛点:
- 写错不报错:
"dept_id"写成"deptId"、"emp_name"写成"empName",编译期毫无察觉,运行时才报 SQL 错误 - 重构不安全:数据库列名改了,字符串不会跟着变,全靠肉眼找
二、LambdaQueryWrapper 是什么
LambdaQueryWrapper 是 QueryWrapper 的升级版,列名改用方法引用(Employee::getEmpName)来表示:
需要导入:
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Employee::getDeptId, 1) // 属性 empId 对应列 emp_id,框架自动转换
.like(Employee::getEmpName, "张")
.orderByDesc(Employee::getEmpSalary);
List<Employee> employeeList = employeeMapper.selectList(wrapper);
生成的 SQL 和上一章完全一样:
==> Preparing: SELECT ... FROM t_emp WHERE dept_id=? AND emp_name LIKE ? ORDER BY emp_salary DESC
好处:
- 属性名
getEmpName写错,编译期直接报错,或者说有提示的情况下很难写错 - 实体属性重命名,这里必须跟着变,重构安全
- 不用记数据库列名,IDE 有自动补全
三、两种写法对比
| 对比项 | QueryWrapper | LambdaQueryWrapper |
|---|---|---|
| 列名写法 | 字符串 "emp_name" | 方法引用 Employee::getEmpName |
| 写错列名 | 编译期不报错,运行时报错 | 编译期直接报错 |
| 重构安全性 | 差 | 好 |
| IDE 提示 | 无 | 有自动补全 |
| 推荐度 | 了解即可 | 推荐使用 |
常用方法名完全一样:
eq / ne / gt / ge / lt / le / between / in / like / isNull / orderByDesc / groupBy / select等,只是第一个参数从字符串换成方法引用。注意:
select方法传方法引用时略有不同(见下文示例 2)。
四、创建 LambdaQueryWrapper 的三种方式
// 方式一:直接 new(最常用)
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
// 方式二:通过 Wrappers 工具类
LambdaQueryWrapper<Employee> wrapper2 = Wrappers.lambdaQuery();
// 方式三:QueryWrapper 转 Lambda(已有 QueryWrapper 时)
QueryWrapper<Employee> old = new QueryWrapper<>();
LambdaQueryWrapper<Employee> wrapper3 = old.lambda();
五、and / or:组合复杂逻辑
多个条件默认用 AND 连接。需要 OR 时显式调用 or():
示例 1:简单 OR
// 查询:部门 1 的员工,或者工资大于 10000 的员工
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Employee::getDeptId, 1)
.or()
.gt(Employee::getEmpSalary, 10000);
==> Preparing: SELECT ... FROM t_emp WHERE dept_id=? OR emp_salary > ?
示例 2:括号嵌套 (A OR B) AND C
直接 or() 会把整条链路打平,但实际需求常是「(部门1 或 工资>10000) 且 姓名包含张」。此时用 嵌套 and/or:
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.eq(Employee::getDeptId, 1)
.or()
.gt(Employee::getEmpSalary, 10000)) // 括号 (A OR B)
.like(Employee::getEmpName, "张"); // AND C
==> Preparing: SELECT ... FROM t_emp WHERE (dept_id=? OR emp_salary > ?) AND emp_name LIKE ?
要点:
and(w -> ...)表示在括号里面条件的前面加 AND and() 方法本身的参数是一个消费型的函数式接口,Lambda 表达式的入参就是前面创建的 LambdaQueryWrapper 对象 Lambda 体中拿到 LambdaQueryWrapper 对象就根据需要拼接条件就行了,它们最终会被放在括号中or(w -> ...)表示在括号里面条件的前面加 OR or() 方法本身的参数是一个消费型的函数式接口,Lambda 表达式的入参就是前面创建的 LambdaQueryWrapper 对象 Lambda 体中拿到 LambdaQueryWrapper 对象就根据需要拼接条件就行了,它们最终会被放在括号中- 括号里的条件可以继续任意嵌套
示例 3:or 中带 and 嵌套
// 查询:工资>10000 的员工,或者(部门1 且 姓名含张)的员工
wrapper.gt(Employee::getEmpSalary, 10000)
.or(w -> w.eq(Employee::getDeptId, 1)
.eq(Employee::getEmpName, "张"));
六、实验:员工多条件搜索
需求
根据前端传来的条件搜索员工,条件是"可选"的:
- 姓名:模糊匹配
- 部门:精确匹配
- 工资下限 / 上限:区间匹配
代码
@Test
public void testSearch() {
// 模拟前端传来的条件(实际开发中这些值来自 Controller 参数)
String name = "张"; // 可能为 null:不限制姓名
Integer deptId = null; // 可能为 null:不限制部门
BigDecimal minSalary = new BigDecimal("6000");
BigDecimal maxSalary = null; // 可能为 null:不限制上限
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
// 第一个 boolean 参数为 false 时,该条件整条被忽略 —— 天然支持可选条件
wrapper.like(name != null, Employee::getEmpName, name)
.eq(deptId != null, Employee::getDeptId, deptId)
.ge(minSalary != null, Employee::getEmpSalary, minSalary)
.le(maxSalary != null, Employee::getEmpSalary, maxSalary)
.orderByDesc(Employee::getEmpSalary);
List<Employee> employeeList = employeeMapper.selectList(wrapper);
employeeList.forEach(System.out::println);
}
重点:eq(boolean condition, ...) 这类重载,第一个 boolean 参数为 false 时整条条件被忽略。这就是动态查询的标配写法,工作中每天都在用。
七、本章小结
- 推荐使用
LambdaQueryWrapper:列名用方法引用,编译期检查,重构安全 - 创建方式:
new LambdaQueryWrapper<>()或Wrappers.lambdaQuery() - 嵌套逻辑:
and(w -> ...)/or(w -> ...)加括号,实现(A OR B) AND C - 可选条件:
eq(boolean, 列, 值)第一个参数控制条件是否生效 - 与 QueryWrapper 方法名通用,学会一个另一个就会了
下一章学习分页查询。