两者都是 MyBatis-Plus 提供的 条件构造器,核心目标是简化 SQL 条件拼接(避免硬编码 SQL 字段名),但核心区别在于 字段引用方式 和 类型安全性,最终生成的 SQL 完全一致。

一、核心区别对比表

特性 QueryWrapper LambdaQueryWrapper
字段引用方式 字符串硬编码(如 "name""age" Lambda 表达式(如 User::getNameUser::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)
);

三、关键补充说明

  1. 功能完全一致:除了字段引用方式不同,两者支持的条件方法(eqgtlikein 等)完全相同,生成的 SQL 也没有差异。
  2. Lambda 依赖 getter:LambdaQueryWrapper 本质是通过 User::getName 这样的方法引用,获取字段名(MyBatis-Plus 会解析 getter 对应的字段,如 getName → name),因此实体类必须有 getter 方法(用 @Data 注解可自动生成)。
  3. 避免硬编码风险:QueryWrapper 的字符串字段名是 “魔法值”,一旦实体类字段改名(如 name → userName),若忘记修改字符串,会导致 SQL 语法错误(Unknown column 'name' in 'where clause'),且编译时无法发现;而 LambdaQueryWrapper 会在编译时检查字段是否存在,重构时 IDE 也会自动同步。

四、选型建议

  • 优先用 LambdaQueryWrapper:生产环境、复杂项目、需要长期维护的代码,优先选择 Lambda 方式,兼顾类型安全和可维护性。
  • 偶尔用 QueryWrapper:快速测试、临时写简单查询、实体类字段频繁变动(且无需重构)的场景,可临时使用字符串方式,省去 Lambda 的语法成本。

本质上,两者是 “同功能、不同字段引用方式” 的工具,核心目标都是简化 MyBatis 的条件拼接,Lambda 方式是更优的工程化选择。


如果您觉得这篇文章对您有帮助,请点赞关注,我会持续分享更多实用的技术文章。如有任何问题,欢迎在评论区留言讨论。

更多推荐