核心概念

  1. LambdaQueryWrapper

    • 基于 Lambda 表达式的查询条件构造器,避免硬编码字段名。
    • 类型安全,编译时检查字段是否存在。
    • 支持链式调用,简化复杂查询。
  2. LambdaUpdateWrapper

    • 基于 Lambda 表达式的更新条件构造器
    • 可同时设置更新字段和条件,避免全字段更新。

操作步骤(详细版)

1. LambdaQueryWrapper 基础使用
// 1. 创建 Wrapper 对象
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();

// 2. 链式构建条件
queryWrapper
    .eq(User::getName, "Alice")          // WHERE name = 'Alice'
    .ge(User::getAge, 18)               // AND age >= 18
    .likeRight(User::getEmail, "alice@") // AND email LIKE 'alice@%'
    .orderByDesc(User::getCreateTime)   // ORDER BY create_time DESC
    .last("LIMIT 10");                  // 拼接 SQL 尾缀(慎用)

// 3. 执行查询
List<User> userList = userMapper.selectList(queryWrapper);
2. LambdaUpdateWrapper 基础使用
// 1. 创建 Wrapper 对象
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();

// 2. 链式构建条件与更新值
updateWrapper
    .set(User::getAge, 25)              // SET age = 25
    .setSql("balance = balance + 100")  // 混合 SQL 表达式
    .eq(User::getName, "Alice")         // WHERE name = 'Alice'
    .in(User::getId, Arrays.asList(1, 2, 3)); // AND id IN (1,2,3)

// 3. 执行更新
int rows = userMapper.update(null, updateWrapper); // 参数 null 表示不基于实体更新
3. 复杂条件组合
// AND/OR 嵌套
queryWrapper
    .and(wrapper -> wrapper
        .eq(User::getStatus, 1)
        .or()
        .gt(User::getScore, 90)
    )
    .or(wrapper -> wrapper
        .between(User::getAge, 20, 30)
        .isNotNull(User::getEmail)
    );
4. 动态条件构建
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
    .eq(StringUtils.isNotBlank(name), User::getName, name) // 动态条件
    .in(ids != null && !ids.isEmpty(), User::getId, ids)   // 集合非空时生效
    .select(User::getId, User::getName); // 只查询特定字段(减少数据传输)

常见错误

  1. NPE(空指针异常)

    • 原因:Lambda 方法引用指向的字段为 null
    • 解决:确保实体类字段有默认值或使用非空条件。
  2. 条件覆盖

    • 错误示例:重复调用 eq 同一字段(后者覆盖前者)。
    wrapper.eq(User::getId, 1).eq(User::getId, 2); // 最终 id=2
    
  3. SQL 注入风险

    • 错误:直接拼接用户输入的字符串到 .last()
    • 解决:用预编译参数(如 .inSql())替代。

注意事项

  1. 避免全表更新/删除

    • 更新/删除操作必须有条件!否则触发 IllegalArgumentException
  2. 字段选择优化

    • .select() 指定字段,避免 SELECT *
  3. Lambda 方法引用限制

    • 仅支持实体类 getter 方法(如 User::getName),不支持静态方法或自定义函数。

使用技巧

  1. 链式与分步结合

    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    if (condition) {
        wrapper.lt(User::getAge, 30); // 分步添加条件
    }
    wrapper.orderByAsc(User::getId);
    
  2. 复用 Wrapper

    • 通过 clone() 复用基础条件:
    LambdaQueryWrapper<User> baseWrapper = new LambdaQueryWrapper<>().eq(User::getStatus, 1);
    LambdaQueryWrapper<User> vipWrapper = baseWrapper.clone().gt(User::getVipLevel, 3);
    
  3. 条件短路优化

    • 使用 boolean 参数控制条件生效:
    wrapper.eq(enableFilter, User::getRole, "admin"); // enableFilter=false 时跳过
    

最佳实践与性能优化

  1. 索引友好查询

    • 避免对索引字段使用 NOT LIKE<>、前模糊匹配(%abc)。
    • 优先使用 eqbetween 等索引匹配条件。
  2. 批量操作优化

    • IN 代替循环单条更新:
    updateWrapper.set(User::getStatus, 0).in(User::getId, idList);
    userMapper.update(null, updateWrapper);
    
  3. 避免大结果集

    • 分页查询必须加 .last("LIMIT start, size") 或使用 Page 对象。
  4. 使用实体类注解

    • 在字段上添加 @TableField(condition = SqlCondition.LIKE) 可简化模糊查询:
    queryWrapper.like(User::getName, "Tom"); // 自动生成 %Tom%
    

总结

  • 核心优势:类型安全、链式调用、动态条件。
  • 关键场景:复杂查询、动态更新、避免硬编码。
  • 避坑指南
    • 始终检查更新条件!
    • 优先 select() 指定字段。
    • 慎用 .last() 防 SQL 注入。

通过链式调用,可大幅提升代码可读性与安全性。结合动态条件构建,轻松应对复杂业务查询需求!