MyBatis-Plus 中「静态 LambdaQuery(Db.lambdaQuery)」和「普通 LambdaQuery」的区别、使用场景,以及自定义 SQL 和条件构造器的选择逻辑,我会从新手视角一步步讲清楚,避免复杂术语(lambdaupdate)。
首先明确核心结论:两者本质都是构建 Lambda 条件查询,只是调用方式、作用域、灵活性不同,先看代码对比,再讲区别。
1. 两种写法的代码示例
假设你有 Address 实体类,对应 address 表:
java
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.Db;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
// 1. 普通 LambdaQuery(基于 Wrapper/Service)
// 方式1:手动 new LambdaQueryWrapper
LambdaQueryWrapper<Address> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Address::getUserId, 1L);
List<Address> addressList1 = addressMapper.selectList(queryWrapper);
// 方式2:基于 Service 层(需要 AddressService 继承 IService<Address>)
List<Address> addressList2 = addressService.lambdaQuery()
.eq(Address::getUserId, 1L)
.list();
// 2. 静态 LambdaQuery(Db 工具类)
List<Address> addressList3 = Db.lambdaQuery(Address.class)
.eq(Address::getUserId, 1L)
.list();
2. 核心区别 & 使用场景
| 特性 | 静态 LambdaQuery(Db.lambdaQuery) | 普通 LambdaQuery(Wrapper/Service) |
|---|---|---|
| 调用方式 | 静态调用 Db.xxx,无需注入 Mapper/Service |
需先注入 xxxMapper 或 xxxService |
| 代码简洁度 | 极简,一行搞定,无需额外依赖 | 稍繁琐,需创建 Wrapper 或注入 Service |
| 灵活性 | 基础查询够用,复杂场景(联表、自定义 SQL)弱 | 可扩展,支持自定义 Wrapper、联表等 |
| 适用场景 | 快速简单查询(单表、少量条件) | 复杂业务查询(多条件、分页、联表) |
| 依赖 | 仅需引入 MyBatis-Plus 核心包 | 需定义 Mapper 接口、Service 接口并注入 |
3. 什么时候用?
-
用 Db.lambdaQuery :临时 / 简单查询场景(比如工具类、测试代码、单表单条件查询),不想写 Mapper/Service,只想快速查数据。例:"查用户 ID=1 的所有地址",无需注入 AddressService,直接
Db.lambdaQuery(Address.class).eq(Address::getUserId, 1).list()。 -
用普通 LambdaQuery :业务核心逻辑、复杂查询场景(比如多条件组合、分页、排序、联表),或需要和 Service/Mapper 层解耦的场景。例:"查用户 ID=1 且状态为启用、按创建时间排序的分页地址列表",用 Service 层的
lambdaQuery更易扩展:java// 复杂查询示例(普通 LambdaQuery) Page<Address> page = new Page<>(1, 10); // 分页:第1页,每页10条 addressService.lambdaQuery() .eq(Address::getUserId, 1L) .eq(Address::getStatus, 1) // 状态启用 .orderByDesc(Address::getCreateTime) .page(page);
二、自定义 SQL vs 条件构造器(Wrapper)
这是 MyBatis-Plus 新手最容易纠结的点:什么时候用条件构造器,什么时候写自定义 SQL?
1. 核心定位
-
条件构造器(LambdaQueryWrapper/QueryWrapper) :MyBatis-Plus 封装的 "无 SQL 写法",通过 Java 代码拼接 WHERE 条件,适合单表、常规条件查询(eq/ne/like/gt/lt 等),无需手写 SQL,降低出错率。
-
自定义 SQL :手写 XML 或注解 SQL,适合复杂场景(联表查询、多表关联、复杂子查询、聚合函数、自定义 JOIN/ON 条件等),条件构造器搞不定的场景都用这个。
2. 代码示例对比
场景 1:条件构造器能搞定的(单表常规查询)
java
// 条件构造器:查用户ID=1、地址包含"北京"的记录
List<Address> list = addressService.lambdaQuery()
.eq(Address::getUserId, 1L)
.like(Address::getDetail, "北京")
.list();
// 底层自动生成 SQL:SELECT * FROM address WHERE user_id = ? AND detail LIKE ?
场景 2:必须自定义 SQL 的(联表查询)
需求:查用户 ID=1 的用户信息 + 对应的默认地址(关联 user 表和 address 表)。
java
// 1. Mapper 接口定义自定义 SQL(注解方式)
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT u.*, a.detail AS default_address " +
"FROM user u " +
"LEFT JOIN address a ON u.id = a.user_id AND a.is_default = 1 " +
"WHERE u.id = #{userId}")
UserVO getUserWithDefaultAddress(@Param("userId") Long userId);
}
// 2. 调用
UserVO userVO = userMapper.getUserWithDefaultAddress(1L);
3. 选择原则(新手直接套)
| 场景类型 | 选条件构造器 | 选自定义 SQL |
|---|---|---|
| 表关联 | 单表 | 多表联查(JOIN/LEFT JOIN) |
| 条件复杂度 | 常规条件(eq/like/gt/ 排序) | 复杂子查询、聚合函数(sum/count/group by) |
| SQL 灵活性 | 低(框架封装) | 高(完全自定义) |
| 维护成本 | 低(改 Java 代码即可) | 高(需维护 SQL 语法) |
4. 进阶:条件构造器 + 自定义 SQL 结合用
如果既想要条件构造器的灵活(动态拼接 WHERE 条件),又需要自定义 SQL(比如联表),MyBatis-Plus 支持混合使用:
java
// Mapper 接口(自定义 SQL + 条件构造器)
public interface AddressMapper extends BaseMapper<Address> {
@Select("SELECT a.*, u.username FROM address a LEFT JOIN user u ON a.user_id = u.id ${ew.customSqlSegment}")
List<AddressVO> selectAddressWithUser(@Param(Constants.WRAPPER) LambdaQueryWrapper<Address> wrapper);
}
// 调用:用条件构造器拼条件,自定义 SQL 做联表
LambdaQueryWrapper<Address> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Address::getUserId, 1L).like(Address::getDetail, "北京");
List<AddressVO> list = addressMapper.selectAddressWithUser(wrapper);
总结
1. 静态 vs 普通 LambdaQuery
Db.lambdaQuery:简单场景速查,无需注入 Mapper/Service,代码极简;- 普通 LambdaQuery(Wrapper/Service):复杂业务查询,灵活扩展,适配分页、多条件、排序等场景。
2. 条件构造器 vs 自定义 SQL
- 条件构造器:单表常规查询优先用,不用写 SQL,维护简单;
- 自定义 SQL:多表联查、复杂子查询、聚合函数 必须用,灵活性最高;
- 进阶场景可结合两者:自定义 SQL 做联表,条件构造器动态拼 WHERE 条件。
简单记:能不用写 SQL 就用条件构造器,搞不定了就写自定义 SQL;能少写代码就用 Db 静态查询,业务核心逻辑就用 Service 层的 LambdaQuery。