在Spring Boot项目中,MyBatis-Plus作为增强工具包,极大简化了数据库操作。然而,面对多种Wrapper写法,许多开发者往往陷入选择困难或随意使用的误区。本文将深入剖析四种Lambda写法的核心差异,帮助你在不同场景下做出最优选择。
这是最直接的Lambda表达式写法,通过实体类方法引用替代字符串字段名,有效避免硬编码错误:
java复制LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getName, "张")
.lt(User::getAge, 30);
List<User> users = userMapper.selectList(wrapper);
特点:
这种写法保留了QueryWrapper的灵活性,同时增加了Lambda支持:
java复制QueryWrapper<User> wrapper = new QueryWrapper<User>().lambda()
.like(User::getName, "王")
.and(w -> w.gt(User::getAge, 20).or().isNotNull(User::getEmail));
适用场景:
MyBatis-Plus 3.x引入的工厂方法,代码更简洁:
java复制LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
.between(User::getAge, 20, 30)
.orderByAsc(User::getCreateTime);
优势:
直接关联Mapper的链式调用方式,适合单表操作:
java复制List<User> users = new LambdaQueryChainWrapper<>(userMapper)
.like(User::getName, "李")
.ge(User::getAge, 25)
.list();
核心价值:
| 特性 | LambdaQueryWrapper | QueryWrapper().lambda() | Wrappers.lambdaQuery() | LambdaQueryChainWrapper |
|---|---|---|---|---|
| 编译期类型检查 | ✓ | ✓ | ✓ | ✓ |
| 链式调用支持 | ✓ | ✓ | ✓ | ✓✓✓(原生支持) |
| 自定义SQL兼容性 | ✓ | ✓ | ✓ | ✗ |
| 静态方法导入 | ✗ | ✗ | ✓ | ✗ |
| 中间变量需求 | 需要 | 需要 | 需要 | 不需要 |
使用JMH进行微基准测试(单位:ops/ms,越高越好):
java复制@Benchmark
public void testLambdaQueryWrapper(Blackhole bh) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getId, 1L);
bh.consume(userMapper.selectOne(wrapper));
}
@Benchmark
public void testLambdaQueryChainWrapper(Blackhole bh) {
bh.consume(new LambdaQueryChainWrapper<>(userMapper)
.eq(User::getId, 1L)
.one());
}
测试结果:
推荐方案:LambdaQueryChainWrapper
java复制// 查询年龄大于25岁的活跃用户
List<User> activeUsers = new LambdaQueryChainWrapper<>(userMapper)
.gt(User::getAge, 25)
.eq(User::getStatus, 1)
.list();
优势:
推荐方案:LambdaQueryWrapper
java复制LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.nested(w -> w.lt(User::getAge, 18).or().gt(User::getAge, 65))
.and(w -> w.like(User::getName, "张").or().like(User::getName, "王"));
原因:
推荐方案:Wrappers.lambdaQuery()
java复制public LambdaQueryWrapper<User> buildCommonWrapper() {
return Wrappers.lambdaQuery(User.class)
.eq(User::getTenantId, getCurrentTenantId());
}
// 复用基础条件
LambdaQueryWrapper<User> wrapper = buildCommonWrapper()
.ge(User::getCreateTime, LocalDate.now().minusMonths(1));
亮点:
结合@SelectProvider实现动态查询:
java复制@SelectProvider(type = UserSqlProvider.class, method = "selectByWrapper")
List<User> selectByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
// 在Provider中处理Wrapper
public String selectByWrapper(Wrapper<User> wrapper) {
return new SQL()
.SELECT("*")
.FROM("user")
.WHERE(wrapper.getSqlSegment())
.toString();
}
注意:
避免在循环中创建Wrapper:
java复制// 错误示范
for (Long id : idList) {
User user = new LambdaQueryChainWrapper<>(userMapper)
.eq(User::getId, id)
.one();
}
// 正确做法
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.in(User::getId, idList);
List<User> users = userMapper.selectList(wrapper);
合理使用索引提示:
java复制LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, 1)
.last("USE INDEX(idx_status_create_time)");
主要差异:
java复制// JPA等效写法
Specification<User> spec = (root, query, cb) ->
cb.and(
cb.like(root.get("name"), "%张%"),
cb.lessThan(root.get("age"), 30)
);
在实际项目中,根据团队技术栈和业务复杂度选择合适的持久层方案才是关键。对于已经使用MyBatis-Plus的项目,掌握这些Lambda写法可以显著提升代码质量和开发效率。