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 等物理分页插件,你可以在保证代码简洁的同时,获得高性能、高稳定性的分页能力,为应用打下坚实的数据访问基础。


相关文章
|
18小时前
|
存储 安全 数据安全/隐私保护
认识OAuth2.0
OAuth2.0是一种开放授权协议,允许第三方应用在用户授权下安全访问资源,无需获取用户账号密码。其核心是通过令牌(token)机制实现权限控制,广泛用于第三方登录、服务间资源调用等场景。支持多种授权模式,其中授权码模式最安全,适用于Web和移动应用,如微信、QQ登录即基于此模式实现。
认识OAuth2.0
|
17小时前
|
安全 Java 数据库
RememberMe基本用法
本文介绍Spring Security中RememberMe功能的实现原理及优化方案。通过配置自动登录,用户勾选后可持久化会话,避免重复登录。系统通过remember-me令牌识别用户,但存在安全风险。为提升安全性,建议将Token持久化至数据库,并增加二次校验机制,防止令牌泄露导致的安全问题。
RememberMe基本用法
|
18小时前
|
数据安全/隐私保护
RememberMe简介及用法
RememberMe功能并非简单保存用户名密码,而是服务器端维持登录状态的机制。用户关闭浏览器后重新打开,仍可保持登录,提升体验,区别于传统Session会话需重复登录的方式。
|
17小时前
|
安全 Java 数据库
自定义认证实现流程
本文介绍如何在Spring Security中实现自定义用户认证。首先创建自定义UserDetailsService,实现loadUserByUsername方法,从数据库加载用户信息与权限;然后在SecurityConfig中注册该服务,配置登录逻辑与权限规则。通过整合持久层,完成基于数据库的认证流程,重启项目后即可生效。
自定义认证实现流程
|
18小时前
|
安全 Java Spring
DelegatingFilterProxy
本文解析Spring Security核心过滤器DelegatingFilterProxy源码,重点说明其如何通过web.xml配置的springSecurityFilterChain名称,动态获取FilterChainProxy并执行过滤链,揭示Spring安全过滤机制的底层实现原理。
DelegatingFilterProxy
|
18小时前
|
安全 Java 数据安全/隐私保护
2-后端代码
本文介绍Spring Security基础配置:首先定义接口,添加新路由;接着创建安全配置类,通过继承WebSecurityConfigurerAdapter实现权限控制,配置表单登录、认证规则及CSRF关闭等,详解各方法作用,帮助理解安全拦截机制。
|
18小时前
4.2 简化模式测试
通过本地地址访问授权接口,用户登录后无需重复认证,直接返回token。授权页面提示授予read/write权限,选择Approve后跳转回调地址获取授权码,并用其向服务器申请通行令牌(token),完成OAuth流程。
|
20小时前
|
JSON 前端开发 Java
Spring Boot 中常用的 MVC 注解
Spring Boot 开发中,核心注解如 `@RestController`、`@RequestMapping`、`@PathVariable`、`@RequestParam` 和 `@RequestBody` 是构建 RESTful 接口的基础。它们分别用于定义控制器、映射请求路径、获取路径参数、查询参数及请求体数据,掌握后可高效开发 Web 接口,适用于前后端分离架构。
|
18小时前
|
Java 数据库连接 数据库
OAuth2.0实战案例3
本节介绍如何创建OAuth2授权模块,包括项目搭建、依赖导入、配置文件编写及核心类配置,实现基于Spring Security与OAuth2的认证授权功能,支持数据库存储客户端与令牌信息。
|
17小时前
|
安全 Java 关系型数据库
OAuth2.0实战案例2
本节介绍如何创建一个基于Spring Boot的资源服务模块,包括工程搭建、依赖导入(如Web、Security、OAuth2等)、配置文件设置、启动类与Mapper扫描,以及编写简单的商品查询接口,实现基础资源访问功能。

热门文章

最新文章