位置:首页 > Java > MyBatis数据分页实现方式详解与实战技巧

MyBatis数据分页实现方式详解与实战技巧

时间:2026-08-18  |  作者:风起客  |  阅读:0

在 MyBatis 里做数据分页,其实路子就那么几条,从最原始的 SQL 手动拼接,到成熟的插件方案,再到针对大数据的流式处理,各有各的适用场景。下面就把这些方式掰开揉碎讲清楚。

Mybatis实现数据分页的多种方式详解

1. SQL 分页(手动分页)

这是最直接的方式——在 SQL 语句里直接动用数据库自带的分页语法。比如 MySQL 的 LIMITOFFSET,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);
List users = 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);
List users = 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 (Cursor cursor = userMapper.selectByCursor()) {
    for (User user : cursor) {
        // 处理数据
    }
}

注意,流式查询本质上是数据库游标,需要保持数据库连接,且不能同时做太多其他操作。适合数据导出、批量迁移这类场景。

分页方案选择建议:

  • 小数据量(几百到几千条):用 SQL 分页或者 RowBounds 都行,简单够用。
  • 大数据量(几万到几百万):首选分页插件(PageHelper),或者自己写一个自定义拦截器,追求物理分页的性能。
  • 复杂场景(比如需要动态分页、多数据源、流式处理):考虑自定义拦截器或者流式查询。

注意事项

  • 物理分页(插件/拦截器)性能远优于逻辑分页(RowBounds),除非数据量极小,否则别用 RowBounds。
  • 分页插件在遇到复杂 SQL(比如多表 join 带子查询)时,可能会生成错误的 count 语句,建议提前测试或手动指定 count SQL。
  • 不同数据库的分页语法不一样,插件虽然能自动适配,但切换数据库时仍要留意细节,比如 Oracle 的 ROWNUM 和 MySQL 的 LIMIT 在语义上就有细微差别。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多