LambdaQueryWrapper 和 QueryWrapper 的核心区别
·
两者都是 MyBatis-Plus 提供的 条件构造器,核心目标是简化 SQL 条件拼接(避免硬编码 SQL 字段名),但核心区别在于 字段引用方式 和 类型安全性,最终生成的 SQL 完全一致。
一、核心区别对比表
| 特性 | QueryWrapper | LambdaQueryWrapper |
|---|---|---|
| 字段引用方式 | 字符串硬编码(如 "name"、"age") |
Lambda 表达式(如 User::getName、User::getAge) |
| 类型安全 | 无(字段名写错、类型不匹配编译不报错,运行时才暴露) | 有(字段名、类型不匹配直接编译报错) |
| 字段名重构 | 不支持(实体类字段改名后,字符串需手动修改,易遗漏) | 支持(IDE 重构实体字段时,Lambda 表达式自动同步) |
| 代码可读性 | 一般(需对照实体类确认字段名是否正确) | 更高(直接关联实体类方法,语义清晰) |
| 使用前提 | 无需额外依赖,直接使用 | 需实体类字段有 getter 方法(Lambda 表达式依赖 getter);若用 Spring Boot 需确保 MyBatis-Plus 版本 ≥ 3.0.0(默认支持) |
| 适用场景 | 快速测试、简单场景、实体类字段不稳定 | 生产环境、复杂查询、追求类型安全和可维护性 |
二、代码示例对比(以 User 实体为例)
假设实体类 User 如下:
@Data
public class User {
private Long id;
private String name;
private Integer age;
private LocalDateTime createTime;
}
1. QueryWrapper 使用(字符串字段名)
// 拼接条件:name = "张三" AND age > 18 AND createTime BETWEEN 开始时间 AND 结束时间
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "张三") // 字段名用字符串,写错(如 "nam")编译不报错
.gt("age", 18) // 若传入非 Integer 类型(如 "18"),运行时才报错
.between("createTime", LocalDateTime.of(2024, 1, 1), LocalDateTime.now());
List<User> userList = userMapper.selectList(queryWrapper);
2. LambdaQueryWrapper 使用(Lambda 字段引用)
// 同样的条件,用 Lambda 表达式引用字段
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getName, "张三") // 直接关联实体类 getter,字段名不会错
.gt(User::getAge, 18) // 传入非 Integer 类型(如 "18"),编译直接报错
.between(User::getCreateTime, LocalDateTime.of(2024, 1, 1), LocalDateTime.now());
List<User> userList = userMapper.selectList(lambdaQueryWrapper);
3. 更简洁的用法(MyBatis-Plus 工具类)
实际开发中常用 Wrappers 工具类快速创建,无需手动 new:
// QueryWrapper 简化
List<User> list1 = userMapper.selectList(
Wrappers.query()
.eq("name", "张三")
.gt("age", 18)
);
// LambdaQueryWrapper 简化
List<User> list2 = userMapper.selectList(
Wrappers.lambdaQuery()
.eq(User::getName, "张三")
.gt(User::getAge, 18)
);
三、关键补充说明
- 功能完全一致:除了字段引用方式不同,两者支持的条件方法(
eq、gt、like、in等)完全相同,生成的 SQL 也没有差异。 - Lambda 依赖 getter:LambdaQueryWrapper 本质是通过
User::getName这样的方法引用,获取字段名(MyBatis-Plus 会解析 getter 对应的字段,如getName→name),因此实体类必须有 getter 方法(用@Data注解可自动生成)。 - 避免硬编码风险:QueryWrapper 的字符串字段名是 “魔法值”,一旦实体类字段改名(如
name→userName),若忘记修改字符串,会导致 SQL 语法错误(Unknown column 'name' in 'where clause'),且编译时无法发现;而 LambdaQueryWrapper 会在编译时检查字段是否存在,重构时 IDE 也会自动同步。
四、选型建议
- 优先用 LambdaQueryWrapper:生产环境、复杂项目、需要长期维护的代码,优先选择 Lambda 方式,兼顾类型安全和可维护性。
- 偶尔用 QueryWrapper:快速测试、临时写简单查询、实体类字段频繁变动(且无需重构)的场景,可临时使用字符串方式,省去 Lambda 的语法成本。
本质上,两者是 “同功能、不同字段引用方式” 的工具,核心目标都是简化 MyBatis 的条件拼接,Lambda 方式是更优的工程化选择。
如果您觉得这篇文章对您有帮助,请点赞关注,我会持续分享更多实用的技术文章。如有任何问题,欢迎在评论区留言讨论。
更多推荐
所有评论(0)