MyBatis数据分页实现方式详解与实战技巧
时间:2026-08-18 | 作者:风起客 | 阅读:0在 MyBatis 里做数据分页,其实路子就那么几条,从最原始的 SQL 手动拼接,到成熟的插件方案,再到针对大数据的流式处理,各有各的适用场景。下面就把这些方式掰开揉碎讲清楚。
1. SQL 分页(手动分页)
这是最直接的方式——在 SQL 语句里直接动用数据库自带的分页语法。比如 MySQL 的 LIMIT 和 OFFSET,Oracle 的 ROWNUM,都是老面孔了。
示例(MySQL):
SELECT * FROM users LIMIT #{offset}, #{pageSize};
- 优点:简单粗暴,不依赖任何第三方库,写出来就能跑。
- 缺点:偏移量得自己算,而且 SQL 跟数据库绑死了,要是哪天从 MySQL 切到 PostgreSQL,分页代码得全改。
2. RowBounds 分页(逻辑分页)
MyBatis 内置了一个 RowBounds 类,可以直接在 Ja va 代码里指定偏移和条数,SQL 不用动。
RowBounds rowBounds = new RowBounds(offset, pageSize); Listusers = sqlSession.selectList("UserMapper.selectAll", null, rowBounds);
- 优点:代码够简洁,不修改 Mapper 文件。
- 缺点:它其实是先把全量数据查出来,然后在内存里做分页。数据量一上来,性能就会急剧下降,属于典型的“偷懒一时爽,上线火葬场”。
3. 分页插件(物理分页)
既然手动分页麻烦、逻辑分页又废内存,那干脆用插件在 SQL 执行前动态拼接分页逻辑。主流的方案就是 PageHelper,几乎成了 MyBatis 分页的标配。
PageHelper 使用步骤:
添加依赖(Ma ven):
com.github.pagehelper pagehelper-spring-boot-starter 最新版本
配置插件(自动配置或手动):
@Configuration
public class MyBatisConfig {
@Bean
public PageInterceptor pageInterceptor() {
return new PageInterceptor();
}
}
业务代码中使用:
// 开启分页,后续查询会自动添加分页逻辑 PageHelper.startPage(pageNum, pageSize); Listusers = userMapper.selectAll(); // 获取分页信息 PageInfo pageInfo = new PageInfo<>(users);
- 优点:分页逻辑完全透明,开发只管写业务查询,插件会自动帮你在 SQL 后面加上 LIMIT 之类的语句;而且支持多种数据库,性能也到位。
- 缺点:需要引入依赖,偶尔会遇到版本兼容问题(比如跟某些 MyBatis 版本不搭),还有就是复杂 SQL 里嵌套子查询时,分页插件可能会“误伤”。
4. 自定义拦截器
如果 PageHelper 满足不了你的特殊需求(比如要动态决定是否分页、或者分页参数来自请求头),那就自己动手写一个拦截器。实现 Interceptor 接口,拦截 Executor 的 query 方法,在调用前动态修改 SQL。
@Intercepts({@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class CustomPageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 动态修改 SQL,添加分页逻辑
// ...
return invocation.proceed();
}
}
这种方式灵活性最高,但开发成本也大,需要熟悉 MyBatis 的底层原理和 SQL 解析。一般只有底层框架或公共组件才会这么干。
5. 流式查询(大数据量分页)
当数据量达到百万甚至千万级别,传统分页(即便用了物理分页)也会因为频繁的 COUNT 查询和 LIMIT 偏移导致性能瓶颈。这时候可以用 MyBatis 的 Cursor 接口,逐行读取数据,避免一次性加载全量。
try (Cursorcursor = userMapper.selectByCursor()) { for (User user : cursor) { // 处理数据 } }
注意,流式查询本质上是数据库游标,需要保持数据库连接,且不能同时做太多其他操作。适合数据导出、批量迁移这类场景。
分页方案选择建议:
- 小数据量(几百到几千条):用 SQL 分页或者 RowBounds 都行,简单够用。
- 大数据量(几万到几百万):首选分页插件(PageHelper),或者自己写一个自定义拦截器,追求物理分页的性能。
- 复杂场景(比如需要动态分页、多数据源、流式处理):考虑自定义拦截器或者流式查询。
注意事项:
- 物理分页(插件/拦截器)性能远优于逻辑分页(RowBounds),除非数据量极小,否则别用 RowBounds。
- 分页插件在遇到复杂 SQL(比如多表 join 带子查询)时,可能会生成错误的 count 语句,建议提前测试或手动指定 count SQL。
- 不同数据库的分页语法不一样,插件虽然能自动适配,但切换数据库时仍要留意细节,比如 Oracle 的 ROWNUM 和 MySQL 的 LIMIT 在语义上就有细微差别。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- Java异常处理实战:从体系架构到健壮性设计全解
- 时间:2026-08-27
-
- 基于Spring Security实现自动登录的完整指南
- 时间:2026-08-27
-
- VS Code Java开发高效配置清单(可直接复制使用)
- 时间:2026-08-27
-
- JavaSwing实现自定义TablePanel组件(附完整代码)
- 时间:2026-08-27
-
- Java基础攻略:输入输出、方法与数组实战指南
- 时间:2026-08-27
-
- Java反射、枚举、Lambda表达式及泛型通配符实例详解
- 时间:2026-08-27
-
- 30个经典算法题及Java解答(含实例代码)
- 时间:2026-08-27
-
- Spring Data JPA 查询实战:方法命名与 @Query 注解详解
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
