spring boot 分页查询详解
本文详细讲解 spring boot 中两种主流分页方案:mybatis + pagehelper 和 mybatis plus 的实现方式、原理、优缺点及实际应用场景。内容涵盖配置、代码示例、注意事项和对比总结。
一、分页查询概述
分页查询是 web 开发中处理大数据集的核心需求,其本质是 按需加载数据,避免一次性返回全部数据导致的性能问题。实现方式通常分为两类:
- 物理分页:通过 sql 直接限制查询范围(如
limit)。 - 逻辑分页:先查询全量数据,再在内存中截取分页(不推荐)。
spring boot 中常用 物理分页,依赖 mybatis 的插件机制动态修改 sql。
二、mybatis + pagehelper 分页方案
1. 核心依赖
<dependency>
<groupid>com.github.pagehelper</groupid>
<artifactid>pagehelper-spring-boot-starter</artifactid>
<version>1.4.6</version>
</dependency>2. 配置参数(application.yml)
pagehelper: helper-dialect: mysql # 指定数据库方言(mysql/oracle/postgresql) reasonable: true # 合理化分页参数(超出范围时自动修正) support-methods-arguments: true # 支持接口参数传递分页
3. 分页实现代码
service 层
public pageinfo<user> getusersbypage(int pagenum, int pagesize) {
try {
// 开启分页:对紧接的第一个查询生效
pagehelper.startpage(pagenum, pagesize);
list<user> users = usermapper.selectall();
return new pageinfo<>(users); // 包含总条数、总页数等信息
} finally {
pagehelper.clearpage(); // 清理 threadlocal
}
}mapper 接口
@select("select * from user where status = 1")
list<user> selectall();4. 分页原理
- threadlocal 传递参数:
pagehelper.startpage()将分页参数存入当前线程的threadlocal。 - 拦截器重写 sql:mybatis 拦截器自动拼接
limit offset, pagesize。 - 自动执行 count 查询:生成分页数据后,自动查询总记录数。
5. 注意事项
- 调用顺序:
startpage()必须紧贴查询方法,否则分页不生效。 - 线程安全:异步或多线程场景需手动传递分页参数。
- 性能优化:复杂 sql 可自定义 count 查询:
@select("select count(*) from user where status = 1")
long countusers();
// 指定自定义 count 方法
pagehelper.startpage(1, 10).count(true).setcountsql("countusers");三、mybatis plus 分页方案
1. 核心依赖
<dependency>
<groupid>com.baomidou</groupid>
<artifactid>mybatis-plus-boot-starter</artifactid>
<version>3.5.3.1</version>
</dependency>2. 分页插件配置
@configuration
public class mybatisplusconfig {
@bean
public mybatisplusinterceptor mybatisplusinterceptor() {
mybatisplusinterceptor interceptor = new mybatisplusinterceptor();
// 添加分页拦截器,指定数据库类型
interceptor.addinnerinterceptor(new paginationinnerinterceptor(dbtype.mysql));
return interceptor;
}
}3. 分页实现代码
service 层
public ipage<user> getusersbypage(int pagenum, int pagesize) {
// 创建分页对象
page<user> page = new page<>(pagenum, pagesize);
// 执行分页查询(自动处理 sql)
return usermapper.selectpage(page, new querywrapper<user>().eq("status", 1));
}mapper 接口
public interface usermapper extends basemapper<user> {
// 继承 basemapper 默认提供分页方法
}4. 分页原理
- 内置分页拦截器:自动识别
ipage参数,重写 sql。 - 统一分页模型:通过
ipage<t>接口封装分页参数和结果。 - 多数据库支持:根据
dbtype生成不同分页 sql(如 oracle 的 rownum)。
5. 注意事项
- wrapper 条件:分页需结合
querywrapper或自定义 sql。 - 性能优化:大数据量分页需手动优化 count 查询:
// 关闭自动 count 查询 page<user> page = new page<>(pagenum, pagesize, false); list<user> users = usermapper.selectpage(page, wrapper); // 手动执行 count 查询 page.settotal(usermapper.selectcount(wrapper));
四、对比总结
| 对比维度 | mybatis + pagehelper | mybatis plus |
|---|---|---|
| 依赖复杂度 | 仅需 pagehelper 依赖 | 需引入 mybatis plus 全家桶 |
| 配置难度 | 需配置方言、合理化参数 | 仅需定义分页拦截器 |
| 侵入性 | 低(无需修改 mapper) | 高(需继承 basemapper) |
| sql 灵活性 | 支持任意复杂 sql,手动优化空间大 | 简单查询高效,复杂 sql 需自定义 |
| 线程安全 | 依赖 threadlocal,需注意异步场景 | 无线程安全问题(参数传递) |
| 适用场景 | 已有 mybatis 项目,需灵活分页 | 新项目或深度集成 mybatis plus |
五、最佳实践与常见问题
1. 最佳实践
- 简单分页:优先使用 mybatis plus,减少代码量。
- 复杂 sql:选择 pagehelper,灵活控制 sql。
- 性能优化:
- 添加索引(如
create index idx_status on user(status))。 - 避免
select *,仅查询必要字段。 - 大数据量分页使用 游标分页 或 延迟关联。
- 添加索引(如
2. 常见问题
q1:分页不生效
- 原因:
startpage()调用顺序错误或未配置拦截器。 - 解决:确保
startpage()在查询方法前调用,检查依赖和配置。
q2:总条数(total)为 0
- 原因:count 查询未匹配条件或 sql 错误。
- 解决:手动指定 count 方法或检查查询条件。
q3:性能低下
优化:
-- 原始 sql(性能差) select * from orders order by id limit 1000000, 10; -- 优化 sql(延迟关联) select * from orders where id >= (select id from orders order by id limit 1000000, 1) order by id limit 10;
六、附录:完整代码示例
pagehelper 完整示例
// service
public pageinfo<user> getusers(int pagenum, int pagesize) {
try {
pagehelper.startpage(pagenum, pagesize);
list<user> users = usermapper.selectbycondition("active");
return new pageinfo<>(users);
} finally {
pagehelper.clearpage();
}
}
// mapper
@select("select * from user where status = #{status}")
list<user> selectbycondition(string status);mybatis plus 完整示例
// service
public ipage<user> getusers(int pagenum, int pagesize) {
page<user> page = new page<>(pagenum, pagesize);
querywrapper<user> wrapper = new querywrapper<>();
wrapper.eq("status", "active");
return usermapper.selectpage(page, wrapper);
}到此这篇关于springboot项目中分页查询的使用解析的文章就介绍到这了,更多相关springboot分页查询使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论