在 MyBatis 中,分页是查询操作的常见需求。目前主流的实现方式有两种:PageHelper 插件和RowBounds 类。本文将从原理、使用方式、性能等方面进行对比两者的差异。来我们一块看看吧!
一、基本概念与原理
1. RowBounds(MyBatis 原生支持)
- 原理:基于内存分页(逻辑分页)。即先查询出全部数据,再在内存中截取指定范围的结果(类似
List.subList())。 - 局限性:无论查询第几页,都会将符合条件的所有数据先查询出来加载到内存,再进行截取,数据量大时性能极差。
2. PageHelper(第三方插件)
- 原理:基于数据库分页(物理分页)。通过拦截 SQL,自动在 SQL 后添加分页语句(如 MySQL 的
LIMIT、Oracle 的ROWNUM),由数据库直接返回分页结果。 - 优势:只查询当前页所需的数据,减少数据传输和内存占用,性能更占优。
二、使用方式对比
1. RowBounds 使用步骤
(1)Mapper 接口定义
public interface UserMapper {
// 查询所有用户(RowBounds在调用时传入)
List<User> selectAll();
}
(2)XML 映射文件
<select id="selectAll" resultType="com.example.User">
SELECT id, name, age FROM user
</select>
(3)调用方式
通过SqlSession的selectList方法传入RowBounds参数(offset:起始位置,limit:每页条数):
// 获取SqlSession
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
// 分页参数:从第0条开始,查询10条(即第1页,每页10条)
RowBounds rowBounds = new RowBounds(0, 10);
List<User> users = mapper.selectAll(rowBounds);
} finally {
session.close();
}
2. PageHelper 使用步骤
(1)引入依赖(Maven)
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version> <!-- 版本号可根据需求调整 -->
</dependency>
(2)Mapper 接口定义
public interface UserMapper {
List<User> selectAll();
}
(3)XML 映射文件
<select id="selectAll" resultType="com.example.User">
SELECT id, name, age FROM user
</select>
(4)调用方式
通过PageHelper.startPage()方法开启分页,后续的第一个查询会自动被分页:
// 开启分页:第1页,每页10条
PageHelper.startPage(1, 10);
// 执行查询(PageHelper会自动拦截SQL并添加分页条件)
List<User> users = userMapper.selectAll();
// 封装分页结果(包含总条数、总页数等信息)
Page<User> page = (Page<User>) users;
// 分页信息示例
long total = page.getTotal(); // 总条数
int pages = page.getPages(); // 总页数
三、核心差异对比
| 维度 | RowBounds | PageHelper |
|---|---|---|
| 分页方式 | 内存分页(先查全部,再截取) | 物理分页(SQL 层面限制结果范围) |
| 性能 | 数据量大时性能极差 | 性能优异(依赖数据库索引) |
| 支持数据库 | 所有数据库(与 SQL 无关) | 主流数据库(自动适配不同分页语法) |
| 分页信息获取 | 不支持总条数、总页数(需手动查询) | 自动返回总条数、总页数等完整信息 |
| 灵活性 | 仅支持offset和limit | 支持排序、复杂查询分页、嵌套查询分页 |
| 适用场景 | 数据量极小(如几十几百条) | 支持大数据量查询 |
四、优缺点总结
1. RowBounds 的优缺点
-
优点:
- MyBatis 原生支持,无需额外依赖。
- 实现简单,适合快速测试或极小数据量场景。
-
缺点:
- 性能问题:大数据量下会导致 OOM(内存溢出)。
- 功能缺失:无法获取总条数、总页数,分页逻辑需手动实现。
- 不适合生产环境。
2. PageHelper 的优缺点
-
优点:
- 性能优秀:基于数据库分页,减少数据传输和内存占用。
- 功能完善:支持总条数、总页数、排序等,满足复杂分页需求。
- 易用性高:一行代码开启分页,对原有代码侵入性极低。
- 兼容性好:自动适配 MySQL、Oracle、SQL Server 等主流数据库。
-
缺点:
- 需要引入第三方依赖。
- 对复杂 SQL(如多表关联、子查询)的分页支持需注意 SQL 写法(避免拦截失效)。
五、使用建议
-
优先选择 PageHelper:
几乎所有生产环境都应使用 PageHelper,尤其是数据量超过 1000 条的场景。其物理分页机制能显著提升性能,且功能完备。 -
谨慎使用 RowBounds:
仅推荐在数据量极小(如配置表、字典表,数据量 < 1000 条)且无需分页信息的场景下使用,禁止在生产环境的大数据量查询中使用。 -
PageHelper 使用注意事项:
PageHelper.startPage()需在查询方法前调用,且只对后续第一个查询有效。- 复杂 SQL 分页时,建议通过
PageHelper.offsetPage(offset, limit)手动指定偏移量和条数。 - 避免在事务中嵌套使用分页(可能导致分页拦截失效)。
总结
RowBounds 作为 MyBatis 的原生分页方式,仅适合简单测试或极小数据量场景;而 PageHelper 通过物理分页机制,在性能、功能、易用性上全面优于 RowBounds,是生产环境的首选。实际开发中,应根据数据量和业务需求选择合适的分页方案,优先推荐 PageHelper。