一、核心概念
LambdaQueryWrapper 是 MyBatis-Plus 提供的查询条件构造器,通过 Lambda 表达式避免硬编码字段名,提升代码可读性和安全性。
- 优势:
- 类型安全:编译时检查字段名是否存在。
- 智能提示:IDE 自动补全实体类属性。
- 防误写:避免手写
"name"
导致的拼写错误。
二、详细操作步骤(以查询用户为例)
1. 引入依赖(Maven)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.0+</version>
</dependency>
2. 创建实体类
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
3. 创建 Mapper 接口
public interface UserMapper extends BaseMapper<User> {}
4. 使用 LambdaQueryWrapper 构建查询
场景1:基础查询(name = "John" 且 age > 18)
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "John") // 等价于 SQL: name = 'John'
.gt(User::getAge, 18) // age > 18
.select(User::getId, User::getName); // 只查询 id 和 name
List<User> userList = userMapper.selectList(wrapper);
场景2:复杂条件(OR 嵌套)
wrapper.nested(wq -> wq.eq(User::getAge, 20).or().eq(User::getAge, 25))
.likeRight(User::getEmail, "admin@"); // email 以 "admin@" 开头
场景3:排序与分页
wrapper.orderByDesc(User::getAge) // 按年龄倒序
.last("LIMIT 10"); // 手动拼接 SQL(慎用!)
// 配合分页插件
Page<User> page = new Page<>(1, 10); // 第1页,每页10条
Page<User> result = userMapper.selectPage(page, wrapper);
三、常见错误与解决
NPE(NullPointerException)
- 原因:
User::getName
可能被误写为User::getName()
(多加了括号)。 - 解决:正确写法
User::getName
。
- 原因:
字段不存在错误
- 原因:Lambda 表达式引用非实体类属性(如
User::getAddress
但实体无此字段)。 - 解决:检查实体类属性名与方法引用一致性。
- 原因:Lambda 表达式引用非实体类属性(如
误用函数式参数
// 错误!条件被覆盖 wrapper.eq(user.getId() != null, User::getId, user.getId()) // 正确:先判空再构建条件 if (user.getId() != null) { wrapper.eq(User::getId, user.getId()); }
四、注意事项
避免
last()
注入风险
禁止将用户输入直接拼接进last()
:// 危险写法! wrapper.last("ORDER BY " + userInput); // 安全替代:使用 wrapper.orderBy() 系列方法
链式调用中断
每次条件构造后返回新对象,连续操作需保持链式:// 错误!丢失后续条件 LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(...); wrapper.gt(...); // 正确:应连续调用
五、使用技巧
1. 动态条件拼接
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.isNotBlank(name), User::getName, name)
.between(ageMin != null && ageMax != null, User::getAge, ageMin, ageMax);
2. 复用 Wrapper
public LambdaQueryWrapper<User> buildQuery(String name, Integer age) {
return new LambdaQueryWrapper<User>()
.eq(User::getName, name)
.gt(User::getAge, age);
}
3. 快速选择字段
wrapper.select(User.class,
info -> !info.getColumn().equals("password")); // 排除敏感字段
六、最佳实践与性能优化
索引友好查询
- 避免在索引列上使用
!=
、not like
。 - 对
LIKE
查询尽量用likeRight("abc%")
(前缀匹配)。
- 避免在索引列上使用
批量操作优化
使用inSql()
代替循环多次查询:// 低效:循环查询 for (Long id : idList) { mapper.selectById(id); } // 高效:单次查询 wrapper.in(User::getId, idList);
关联查询处理
- 复杂关联查询建议用 XML/注解 SQL。
- 简单关联可用
apply()
拼接 JOIN 语句(需谨慎)。
七、完整示例代码
// 查询邮箱包含 "example" 且年龄在 20-30 之间的用户,按 ID 倒序
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getEmail, "example")
.between(User::getAge, 20, 30)
.orderByDesc(User::getId);
List<User> users = userMapper.selectList(wrapper);
总结
关键点 | 行动指南 |
---|---|
类型安全 | 坚持使用 User::getName 而非 "name" |
动态条件 | 善用 eq(condition, ...) 避免 if 嵌套 |
性能敏感操作 | 优先使用 in() 替代循环单条查询 |
SQL 注入防范 | 禁止未校验参数传入 last() / apply() |
掌握 LambdaQueryWrapper 可大幅提升 MyBatis-Plus 开发效率,结合 Lambda 表达式的优雅性与条件构造的灵活性,能写出更健壮、易维护的数据库操作代码。