【MyBatis-Plus 查询核心对比】:List <泛型> vs IPage < 泛型 > 与 QueryWrapper vs LambdaQueryWrapper 全解析
·
一、查询结果处理:List <泛型> vs IPage < 泛型 >
查询结果的承载方式直接影响数据获取效率与业务适配性,List<泛型>和IPage<泛型>分别对应 “全量数据” 和 “分页数据” 两种核心需求,需根据数据规模和展示场景选择。
1. List <泛型>:全量数据的简单承载
List<泛型>是 Java 集合框架的基础类型,在 MyBatis-Plus 中用于接收所有符合条件的查询结果,不包含分页相关信息,适合数据量较小的场景。
核心特点:
- 结构轻量:直接返回实体对象列表,无额外元数据
- 加载方式:一次性加载所有匹配数据到内存
- 使用门槛:无需额外配置,直接对接
selectList()方法
适用场景:
- 数据量小的基础表查询(如字典表、配置表)
- 需要完整数据集合的批量操作(如数据导出、批量计算)
- 简单的内部查询(如获取当前用户的关联角色列表)
代码示例:
// 1. 基础查询:获取所有状态为“启用”的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 1); // 条件:status=1(启用)
List<User> activeUserList = userMapper.selectList(queryWrapper);
// 2. 带排序的查询:按创建时间倒序获取用户
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.orderByDesc(User::getCreateTime); // 按创建时间倒序
List<User> sortedUserList = userMapper.selectList(lambdaQuery);
// 3. 结果遍历使用
for (User user : activeUserList) {
System.out.println("用户名:" + user.getUsername() + ",状态:" + user.getStatus());
}
2. IPage <泛型>:分页数据的专业解决方案
IPage<泛型>是 MyBatis-Plus 提供的分页专属接口,用于接收分页查询结果,不仅包含当前页数据,还封装了总条数、总页数等关键分页元信息,适合数据量较大的列表场景。
核心特点:
- 元数据完整:包含总记录数(
total)、总页数(pages)、当前页码(current)、每页条数(size) - 性能友好:基于数据库物理分页(如
LIMIT语句),避免全量加载导致的内存压力 - 配置灵活:通过
Page实现类可自定义页码、每页条数,支持分页参数校验
适用场景:
- 前端列表分页展示(如用户管理列表、订单记录列表)
- 大数据量查询(如查询近一年的交易记录)
- 需要分页导航的场景(如 “上一页 / 下一页 / 首页 / 末页” 功能)
代码示例:
// 1. 基础分页查询:第1页,每页10条数据
IPage<User> page = new Page<>(1, 10); // 参数1:当前页码,参数2:每页条数
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("username", "admin"); // 模糊查询:username包含“admin”
IPage<User> userPage = userMapper.selectPage(page, queryWrapper);
// 2. 分页元信息获取与使用
long totalCount = userPage.getTotal(); // 总记录数
long totalPage = userPage.getPages(); // 总页数
int currentPage = (int) userPage.getCurrent(); // 当前页码
int pageSize = (int) userPage.getSize(); // 每页条数
System.out.println("总记录数:" + totalCount + ",总页数:" + totalPage);
// 3. 当前页数据获取与使用
List<User> currentPageData = userPage.getRecords(); // 当前页数据列表
for (User user : currentPageData) {
System.out.println("页码" + currentPage + ":" + user.getUsername());
}
// 4. Lambda条件+分页:更安全的字段引用
LambdaQueryWrapper<User> lambdaPageQuery = new LambdaQueryWrapper<>();
lambdaPageQuery.ge(User::getAge, 18); // 条件:age≥18
IPage<User> lambdaUserPage = userMapper.selectPage(new Page<>(2, 10), lambdaPageQuery);
3. 两者核心区别与选择建议
| 对比维度 | List <泛型> | IPage <泛型> |
|---|---|---|
| 数据范围 | 全量匹配数据 | 仅当前页数据 |
| 分页元信息 | 无 | 包含 total、pages 等完整元数据 |
| 内存占用 | 随数据量增大而增加 | 固定为 “每页条数” 级别 |
| 数据库压力 | 可能触发全表扫描(数据量大时) | 仅扫描当前页数据 |
| 对接方法 | selectList() |
selectPage() |
选择建议:
- 数据量≤1000 条且无需分页 → 用
List<泛型> - 数据量 > 1000 条或需分页展示 → 必须用
IPage<泛型> - 不确定数据量增长趋势时,优先选择
IPage<泛型>(避免后期重构)
二、查询条件构造:QueryWrapper vs LambdaQueryWrapper
查询条件构造是动态 SQL 的核心,QueryWrapper和LambdaQueryWrapper是 MyBatis-Plus 的两大构造工具,核心区别在于 “字段引用方式”,直接影响代码安全性和可维护性。
1. QueryWrapper:基于数据库字段名的快速构造
QueryWrapper通过数据库字段名(字符串) 指定查询条件,写法简洁直接,适合快速构建简单查询。
核心特点:
- 字段引用:直接写数据库字段名(如
"username") - 语法简洁:无需依赖实体类方法,上手快
- 校验机制:无编译时校验(字段名写错需运行时发现)
适用场景:
- 临时测试查询(如快速验证数据是否存在)
- 数据库表结构稳定、字段名简单的场景
- 简单条件查询(如单字段等值匹配)
代码示例:
// 1. 等值查询:获取username为“张三”的用户
QueryWrapper<User> eqQuery = new QueryWrapper<>();
eqQuery.eq("username", "张三"); // WHERE username = '张三'
User zhangsan = userMapper.selectOne(eqQuery);
// 2. 多条件组合:status=1且age≥18且create_time在2024年
QueryWrapper<User> multiQuery = new QueryWrapper<>();
multiQuery.eq("status", 1) // 条件1:status=1
.ge("age", 18) // 条件2:age≥18
.between("create_time", "2024-01-01", "2024-12-31") // 条件3:时间范围
.orderByDesc("create_time"); // 按创建时间倒序
List<User> multiConditionList = userMapper.selectList(multiQuery);
// 3. 动态条件:参数不为空时才添加条件
String keyword = "admin"; // 假设从前端传入的搜索关键词
QueryWrapper<User> dynamicQuery = new QueryWrapper<>();
if (keyword != null && !keyword.isEmpty()) {
dynamicQuery.like("username", keyword); // 关键词非空时,添加模糊查询
}
List<User> dynamicResultList = userMapper.selectList(dynamicQuery);
2. LambdaQueryWrapper:类型安全的条件构造
LambdaQueryWrapper基于实体类方法引用(如User::getUsername)指定字段,支持编译时字段校验,能有效避免字段名拼写错误,是长期维护项目的优选。
核心特点:
- 字段引用:通过实体类 getter 方法引用(如
User::getUsername) - 类型安全:编译时校验字段合法性(字段不存在则编译报错)
- 重构友好:实体类字段名变更时,可同步自动重构
- 用法灵活:支持与
QueryWrapper相同的所有条件方法
适用场景:
- 长期维护的项目(避免后期字段变更导致的隐藏 bug)
- 字段名复杂或易拼写错误的场景(如
user_registration_time) - 复杂条件查询(如多表关联、嵌套条件)
- 团队协作开发(统一字段引用方式,减少沟通成本)
代码示例:
// 1. 基础用法:获取age≥18且status=1的用户
LambdaQueryWrapper<User> baseLambdaQuery = new LambdaQueryWrapper<>();
baseLambdaQuery.ge(User::getAge, 18) // 条件:age≥18(引用User的getAge()方法)
.eq(User::getStatus, 1); // 条件:status=1
List<User> adultActiveUserList = userMapper.selectList(baseLambdaQuery);
// 2. 简化用法:通过Service的lambdaQuery()直接构建
// 无需手动创建LambdaQueryWrapper,直接链式调用
List<User> quickResultList = userService.lambdaQuery()
.like(User::getUsername, "test") // 模糊查询:username包含“test”
.orderByAsc(User::getUsername) // 按用户名升序
.list(); // 执行查询并返回List
// 3. 动态条件简化:无需if判断,直接传条件表达式
String searchName = "张三";
Date startTime = new SimpleDateFormat("yyyy-MM-dd").parse("2024-01-01");
List<User> simpleDynamicList = userService.lambdaQuery()
// 第一个参数为“条件是否生效”,true则添加该条件
.like(searchName != null, User::getUsername, searchName)
.ge(startTime != null, User::getCreateTime, startTime)
.list();
// 4. 嵌套条件:OR与AND组合(例:(username含“admin” OR email含“admin”) AND status=1)
LambdaQueryWrapper<User> nestedLambdaQuery = new LambdaQueryWrapper<>();
nestedLambdaQuery.nested(q -> q.like(User::getUsername, "admin")
.or()
.like(User::getEmail, "admin"))
.eq(User::getStatus, 1);
List<User> nestedResultList = userMapper.selectList(nestedLambdaQuery);
3. 两者核心区别与选择建议
| 对比维度 | QueryWrapper | LambdaQueryWrapper |
|---|---|---|
| 字段引用方式 | 数据库字段名字符串 | 实体类方法引用(如 User::getUsername) |
| 编译时校验 | 无(字段错写运行时报错) | 有(字段错写编译不通过) |
| 重构支持 | 差(字段名变更需手动修改) | 好(实体类字段变更同步重构) |
| 学习成本 | 低(直接写字段名) | 稍高(需了解 Lambda 表达式) |
| 字段映射适配 | 需手动匹配数据库字段(如 @TableField) | 自动适配实体类与数据库字段映射 |
选择建议:
- 优先使用
LambdaQueryWrapper:尤其新项目、长期维护项目,利用类型安全减少 bug - 临时查询 / 简单场景:可用
QueryWrapper提升编码速度(需确保字段名正确) - 字段名与实体类属性不一致时(如
@TableField(value = "user_name")):强制用LambdaQueryWrapper,无需关心数据库实际字段名
三、总结
- 结果处理选择:根据数据量和分页需求决定 —— 小数据量用
List<泛型>,大数据量 / 需分页用IPage<泛型>,后者需配合Page对象初始化页码和每页条数。 - 条件构造选择:优先用
LambdaQueryWrapper保障类型安全和可维护性,简单临时查询可用QueryWrapper;两者均可通过链式调用构建复杂条件。 - 组合使用原则:
QueryWrapper/LambdaQueryWrapper可与List/IPage任意组合(如LambdaQueryWrapper+IPage实现分页 + 类型安全条件),需根据业务场景灵活搭配。
掌握这两组工具的核心区别与用法,能显著提升 MyBatis-Plus 查询代码的效率、安全性和可维护性,适配不同场景下的查询需求。
如果您觉得这篇文章对您有帮助,请点赞关注,我会持续分享更多实用的技术文章。如有任何问题,欢迎在评论区留言讨论。
更多推荐


所有评论(0)