mybatis-plus 常用方法之lambdaQuery, LambdaQueryWrapper
在 Spring Boot 中,只要让 Service 实现类继承 MyBatis-Plus 提供的 ServiceImpl,就可以直接使用 lambdaQuery() 方法进行链式查询
核心前提:正确继承
要使用 lambdaQuery(),您的 Service 接口和实现类必须遵循以下继承规则:
Service 接口:需要继承 IService
Service 实现类:需要继承 ServiceImpl<M, T>,其中 M 是 Mapper 接口,T 是实体类。
@ServicepublicclassSysUserServiceImplextendsServiceImpl<SysUserMapper,SysUser>implementsISysUserService{// 继承后,自动拥有 lambdaQuery()、list()、getById() 等方法}lambdaQuery() 的使用方式
- 动态条件查询列表(支持条件判断,类似 MyBatis 的 标签)
List<SysUser>users=this.lambdaQuery()// 当 userName 不为空时,才拼接 like 条件.like(StringUtils.isNotBlank(userName),SysUser::getUserName,userName)// 当 status 不为空时,才拼接 eq 条件.eq(StringUtils.isNotBlank(status),SysUser::getStatus,status).list();// 最后调用 list() 执行查询- 查询单条记录
SysUseruser=this.lambdaQuery().eq(SysUser::getId,userId).one();// 调用 one() 获取单条记录- 查询数量:
Longcount=this.lambdaQuery().eq(SysUser::getStatus,"1").count();// 调用 count() 获取数量在 MyBatis-Plus 中,this.lambdaQuery() 返回的是一个 LambdaQueryChainWrapper 对象。在这个链式调用中,你可以拼接的方法主要分为三大类:
1. 条件构造方法(中间拼接)
这类方法用于动态组装 SQL 的 WHERE 子句。它们支持 Lambda 表达式(如 Entity::getField),并且通常支持传入一个 boolean 类型的条件参数,只有当条件为 true 时,该 SQL 片段才会被拼接到最终语句中。
等值与不等值:eq (等于), ne (不等于)
大小比较:gt (大于), ge (大于等于), lt (小于), le (小于等于)
模糊查询:like (包含), likeLeft (右模糊), likeRight (左模糊), notLike
范围查询:between, notBetween
包含查询:in, notIn
空值判断:isNull, isNotNull
逻辑嵌套:and (AND 嵌套), or (OR 嵌套)
其他:orderByDesc (降序), orderByAsc (升序), select (指定查询列) 等
2. 结果集获取方法(链式结尾)
这是链式调用的终结方法。MyBatis-Plus 会根据你最后调用的这个方法,来决定执行什么类型的 SQL 以及返回什么格式的数据:
.one():获取单条记录。如果查询到多条记录,会抛出 TooManyResultsException 异常。
.list():获取列表数据,返回 List 集合。
.count():获取统计数量,返回 Long 或 Integer。
.page(IPage page):进行分页查询,返回分页对象(需传入分页参数)。
.getWrapper():获取当前链式构建的底层 LambdaQueryWrapper 对象(适用于需要将条件传递给其他复杂方法的场景)。
3. 实体注入方法
例子:
场景一:动态条件查询列表
List<User>users=this.lambdaQuery()// 只有当 username 不为空时,才拼接 like 条件.like(StringUtils.isNotBlank(username),User::getUsername,username)// 只有当 status 不为空时,才拼接 eq 条件.eq(status!=null,User::getStatus,status)// 以 list() 结尾,返回集合.list();场景二:查询单条并排序
Useruser=this.lambdaQuery().eq(User::getPhone,"13800138000").orderByDesc(User::getCreateTime)// 按创建时间倒序.one();// 以 one() 结尾,返回单条记录场景三:获取底层 Wrapper
// 获取构建好的 Wrapper,用于传给其他方法LambdaQueryWrapper<User>wrapper=this.lambdaQuery().eq(User::getStatus,1).getWrapper();.setEntity(entity):可以将一个实体对象传入,MyBatis-Plus 会将该实体中非空的属性默认作为 eq (等于) 的查询条件拼接到 SQL 中。
LambdaQueryWrapper
除了 lambdaQuery() 链式调用,您也可以单独创建 LambdaQueryWrapper,然后传给 Service 或 Mapper 的方法中,效果是一样的:
LambdaQueryWrapper 是 MyBatis-Plus 框架中提供的一个非常核心的查询条件构造器。它基于 Java 8 的 Lambda 表达式特性,允许开发者通过实体类的属性引用来构建 SQL 的 WHERE 查询条件,从而完全替代手写 SQL 或传统的字符串拼接方式。
// 创建 WrapperLambdaQueryWrapper<SysUser>wrapper=newLambdaQueryWrapper<>();wrapper.like(SysUser::getUserName,"admin");// 方式一:在 Service 层使用List<SysUser>list1=this.list(wrapper);// 方式二:在 Mapper 层使用List<SysUser>list2=this.baseMapper.selectList(wrapper);| 方法 | 说明 | 示例 |
|---|---|---|
eq(字段, 值) | 等于= | .eq(User::getId, 1) |
ne(字段, 值) | 不等于!= | .ne(User::getStatus, 0) |
gt(字段, 值) | 大于> | .gt(User::getAge, 18) |
ge(字段, 值) | 大于等于>= | .ge(User::getAge, 18) |
lt(字段, 值) | 小于< | .lt(User::getAge, 60) |
le(字段, 值) | 小于等于<= | .le(User::getAge, 60) |
like(字段, 值) | 模糊匹配LIKE '%值%' | .like(User::getName, "张") |
likeLeft(字段, 值) | 左模糊LIKE '%值' | .likeLeft(User::getName, "三") |
likeRight(字段, 值) | 右模糊LIKE '值%' | .likeRight(User::getName, "张") |
in(字段, 集合) | IN 查询 | .in(User::getId, Arrays.asList(1,2,3)) |
isNull(字段) | 为 NULL | .isNull(User::getEmail) |
isNotNull(字段) | 不为 NULL | .isNotNull(User::getEmail) |
orderByAsc(字段) | 升序 | .orderByAsc(User::getAge) |
orderByDesc(字段) | 降序 | .orderByDesc(User::getCreateTime) |
between(字段, 值1, 值2) | 区间查询 | .between(User::getAge, 18, 60) |
and(条件) | 嵌套 AND | .and(w -> w.gt(User::getAge, 18).lt(User::getAge, 60)) |
or() | OR | .eq(User::getId, 1).or().eq(User::getId, 2) |
select(字段...) | 指定查询列 | .select(User::getId, User::getName) |
总结来说,继承 ServiceImpl 后,无论是使用 this.lambdaQuery().eq(…).list() 的链式写法,还是 this.list(wrapper) 的传参写法,都能极大简化单表 CRUD 的代码量,并提升重构时的安全性。
注意事项
- 适用场景:LambdaQueryWrapper 主要用于单表的复杂动态查询。如果涉及多表关联查询,通常还需要结合 MyBatis 的 XML 或自定义 SQL 来实现。
- 安全性:使用 Lambda 表达式可以有效避免 SQL 注入风险,但在使用某些允许传入 SQL 片段的方法(如 last() 或 inSql())时,仍需注意防范安全漏洞。
