核心概念
LambdaQueryWrapper
- 基于 Lambda 表达式的查询条件构造器,避免硬编码字段名。
- 类型安全,编译时检查字段是否存在。
- 支持链式调用,简化复杂查询。
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); // 只查询特定字段(减少数据传输)
常见错误
NPE(空指针异常)
- 原因:Lambda 方法引用指向的字段为
null
。 - 解决:确保实体类字段有默认值或使用非空条件。
- 原因:Lambda 方法引用指向的字段为
条件覆盖
- 错误示例:重复调用
eq
同一字段(后者覆盖前者)。
wrapper.eq(User::getId, 1).eq(User::getId, 2); // 最终 id=2
- 错误示例:重复调用
SQL 注入风险
- 错误:直接拼接用户输入的字符串到
.last()
。 - 解决:用预编译参数(如
.inSql()
)替代。
- 错误:直接拼接用户输入的字符串到
注意事项
避免全表更新/删除
- 更新/删除操作必须有条件!否则触发
IllegalArgumentException
。
- 更新/删除操作必须有条件!否则触发
字段选择优化
- 用
.select()
指定字段,避免SELECT *
。
- 用
Lambda 方法引用限制
- 仅支持实体类
getter
方法(如User::getName
),不支持静态方法或自定义函数。
- 仅支持实体类
使用技巧
链式与分步结合
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); if (condition) { wrapper.lt(User::getAge, 30); // 分步添加条件 } wrapper.orderByAsc(User::getId);
复用 Wrapper
- 通过
clone()
复用基础条件:
LambdaQueryWrapper<User> baseWrapper = new LambdaQueryWrapper<>().eq(User::getStatus, 1); LambdaQueryWrapper<User> vipWrapper = baseWrapper.clone().gt(User::getVipLevel, 3);
- 通过
条件短路优化
- 使用
boolean
参数控制条件生效:
wrapper.eq(enableFilter, User::getRole, "admin"); // enableFilter=false 时跳过
- 使用
最佳实践与性能优化
索引友好查询
- 避免对索引字段使用
NOT LIKE
、<>
、前模糊匹配(%abc
)。 - 优先使用
eq
、between
等索引匹配条件。
- 避免对索引字段使用
批量操作优化
- 用
IN
代替循环单条更新:
updateWrapper.set(User::getStatus, 0).in(User::getId, idList); userMapper.update(null, updateWrapper);
- 用
避免大结果集
- 分页查询必须加
.last("LIMIT start, size")
或使用Page
对象。
- 分页查询必须加
使用实体类注解
- 在字段上添加
@TableField(condition = SqlCondition.LIKE)
可简化模糊查询:
queryWrapper.like(User::getName, "Tom"); // 自动生成 %Tom%
- 在字段上添加
总结
- 核心优势:类型安全、链式调用、动态条件。
- 关键场景:复杂查询、动态更新、避免硬编码。
- 避坑指南:
- 始终检查更新条件!
- 优先
select()
指定字段。 - 慎用
.last()
防 SQL 注入。
通过链式调用,可大幅提升代码可读性与安全性。结合动态条件构建,轻松应对复杂业务查询需求!