MyBatis 分页机制详解:从 RowBounds 到物理分页实践

简介: MyBatis分页策略解析:逻辑分页(RowBounds)将全量数据加载至内存,仅适用于小数据量;物理分页通过SQL层面限制返回数据,性能更优。推荐使用PageHelper插件,自动适配数据库方言,一行代码实现高效分页,避免OOM风险,提升系统稳定性。

在 Web 开发中,分页是处理大量数据展示的必备功能。MyBatis 本身不强制提供分页实现,但支持多种分页策略,主要分为 逻辑分页(内存分页)物理分页(数据库分页)。理解它们的原理与适用场景,对系统性能和稳定性至关重要。


一、逻辑分页:MyBatis 自带的 RowBounds

RowBounds 是 MyBatis 提供的内置分页工具,属于逻辑分页——即先查询出全部结果集,再在 Java 内存中截取指定范围的数据。

使用示例:
// Mapper 接口(无需特殊定义)
List<User> selectAllUsers();
// Service 层调用
int offset = (pageNum - 1) * pageSize; // 起始行
int limit = pageSize;                  // 获取条数
RowBounds rowBounds = new RowBounds(offset, limit);
List<User> users = userMapper.selectAllUsers(rowBounds);
底层原理:
  • 执行原始 SQL(如 SELECT * FROM user),获取完整 ResultSet
  • MyBatis 遍历结果集,跳过 offset 条,再取 limit 条;
  • 未生成带 LIMIT 的 SQL,数据库仍返回全部数据。

⚠️ 缺点

  • 内存开销大:若表有 100 万条数据,即使只取第 1 页,也会加载全部到内存;
  • 性能差:大数据量下响应慢,甚至引发 OutOfMemoryError
  • 网络传输浪费:大量无用数据在网络中传输。

适用场景

仅适用于数据量极小(如配置表、字典表)且分页需求简单的场景。


二、物理分页:真正的高效分页

物理分页通过在 SQL 层面添加分页语句(如 LIMITROWNUM),让数据库只返回所需数据,大幅减少 I/O、内存和网络开销。

常见的物理分页实现方式包括:

1. 手写 SQL 分页

直接在 Mapper XML 中编写带分页关键字的 SQL(需适配不同数据库):

<!-- MySQL -->
<select id="selectUsersByPage" resultType="User">
  SELECT * FROM user
  LIMIT #{offset}, #{limit}
</select>
<!-- Oracle -->
<select id="selectUsersByPage" resultType="User">
  SELECT * FROM (
    SELECT ROWNUM rn, t.* FROM (
      SELECT * FROM user ORDER BY id
    ) t WHERE ROWNUM &lt;= #{endRow}
  ) WHERE rn > #{startRow}
</select>

✅ 优点:完全可控;

❌ 缺点:需为不同数据库维护不同 SQL,维护成本高。


2. 第三方插件:PageHelper(推荐)

PageHelper 是最流行的 MyBatis 分页插件,自动识别数据库类型并重写 SQL。

使用步骤:
  1. 引入依赖(Maven):
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.4.6</version>
</dependency>
  1. 在查询前开启分页:
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAllUsers(); // 原始查询方法,无需改写
  1. 获取分页信息(可选):
PageInfo<User> pageInfo = new PageInfo<>(users);
long total = pageInfo.getTotal(); // 总记录数
插件原理:
  • 拦截 SQL 执行;
  • 自动拼接分页语句(MySQL → LIMIT,Oracle → ROWNUM,SQL Server → OFFSET FETCH 等);
  • 额外执行一条 COUNT(*) 查询总条数

优势

  • 一行代码实现分页;
  • 自动适配主流数据库;
  • 返回完整分页元数据(总页数、是否首页等)。

3. 数组分页(伪物理分页)

在 DAO 层查出全部数据,Service 层用 List.subList() 截取:

public List<Student> queryStudentsByArray(int currPage, int pageSize) {
    List<Student> all = studentMapper.queryAll();
    int start = (currPage - 1) * pageSize;
    int end = Math.min(start + pageSize, all.size());
    return all.subList(start, end);
}

⚠️ 本质仍是逻辑分页!只是手动实现了 RowBounds 的功能,同样存在内存溢出风险,不推荐用于生产环境。


4. 自定义拦截器分页

通过实现 MyBatis Interceptor 接口,拦截特定命名的查询(如 *ByPage),动态拼接 LIMIT

✅ 适合有统一规范的团队;

❌ 开发成本较高,需处理 SQL 解析、方言适配等细节。


三、逻辑分页 vs 物理分页:对比总结

对比项 逻辑分页(RowBounds) 物理分页(PageHelper / 手写 SQL)
数据加载 全量加载到内存 数据库只返回当前页
内存占用 高(随总数据量增长) 低(仅当前页)
网络传输 大量无用数据 仅有效数据
性能(大数据) 极差,可能 OOM 优秀
数据库压力 高(全表扫描) 低(利用索引+分页)
适用场景 小表、配置类数据 所有业务主表

📌 核心原则

物理分页总是优先于逻辑分页。除非数据量极小(< 1000 条),否则应避免使用 RowBoundssubList 分页。


通过合理选择分页策略,尤其是采用 PageHelper 等物理分页插件,你可以在保证代码简洁的同时,获得高性能、高稳定性的分页能力,为应用打下坚实的数据访问基础。


相关文章
|
8月前
|
SQL 缓存 NoSQL
深入骨髓!MyBatis二级缓存实战指南
本文全面解析MyBatis二级缓存的核心原理与实践应用。作为Mapper级别的缓存机制,二级缓存能有效降低数据库压力,提升查询性能。文章详细介绍了二级缓存的启用配置、工作流程、源码实现及事务一致性机制,并针对分布式环境提出了Redis集成方案。同时总结了适用场景与禁用场景,提供缓存策略选择建议,强调数据一致性的保障措施。最后给出最佳实践指南,包括缓存容量设置、性能优化技巧及常见问题解决方案,帮助开发者合理利用二级缓存实现性能优化。
869 7
|
8月前
|
缓存 Java 数据库连接
MyBatis 常见配置详解:属性优先级、执行器与多环境支持
MyBatis 是优秀的持久层框架,简化数据库操作。本文详解配置属性加载优先级(代码 &gt; 外部文件 &gt; 内联)、常用全局设置(如缓存、延迟加载)及多环境多数据源配置方法,助力提升系统稳定与性能。
|
缓存 Java 数据库连接
Mybatis一级缓存、二级缓存详讲
本文介绍了MyBatis中的查询缓存机制,包括一级缓存和二级缓存。一级缓存基于同一个SqlSession对象,重复查询相同数据时可直接从缓存中获取,减少数据库访问。执行`commit`操作会清空SqlSession缓存。二级缓存作用于同一namespace下的Mapper对象,支持数据共享,需手动开启并实现序列化接口。二级缓存通过将数据存储到硬盘文件中实现持久化,为优化性能,通常在关闭Session时批量写入缓存。文章还说明了缓存的使用场景及注意事项。
1147 7
Mybatis一级缓存、二级缓存详讲
|
8月前
|
Java 应用服务中间件 Maven
Spring Boot开发环境搭建和项目启动
本节讲解JDK配置、Spring Boot工程构建与项目启动,涵盖IDEA和官方方式创建项目、Maven及编码设置,分析项目结构,并通过简单Controller验证启动成功,快速入门Spring Boot开发。
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
3325 1
|
10月前
|
机器学习/深度学习 监控 PyTorch
68_分布式训练技术:DDP与Horovod
随着大型语言模型(LLM)规模的不断扩大,从早期的BERT(数亿参数)到如今的GPT-4(万亿级参数),单卡训练已经成为不可能完成的任务。分布式训练技术应运而生,成为大模型开发的核心基础设施。2025年,分布式训练技术已经发展到相当成熟的阶段,各种优化策略和框架不断涌现,为大模型训练提供了强大的支持。
1147 0
|
SQL Java 数据安全/隐私保护
发现问题:Mybatis-plus的分页总数为0,分页功能失效,以及多租户插件的使用。
总的来说,使用 Mybatis-plus 确实可以极大地方便我们的开发,但也需要我们理解其工作原理,掌握如何合适地使用各种插件。分页插件和多租户插件是其中典型,它们的运用可以让我们的代码更为简洁、高效,理解和掌握好它们的用法对我们的开发过程有着极其重要的意义。
1131 15
|
SQL 存储 大数据
Flink 基础详解:大数据处理的强大引擎
Apache Flink 是一个分布式流批一体化的开源平台,专为大规模数据处理设计。它支持实时流处理和批处理,具有高吞吐量、低延迟特性。Flink 提供统一的编程抽象,简化大数据应用开发,并在流处理方面表现卓越,广泛应用于实时监控、金融交易分析等场景。其架构包括 JobManager、TaskManager 和 Client,支持并行度、水位线、时间语义等基础属性。Flink 还提供了丰富的算子、状态管理和容错机制,如检查点和 Savepoint,确保作业的可靠性和一致性。此外,Flink 支持 SQL 查询和 CDC 功能,实现实时数据捕获与同步,广泛应用于数据仓库和实时数据分析领域。
11499 42
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
36725 1