MyBatis两种分页方式知道吗?

249 阅读4分钟

在 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)调用方式

通过SqlSessionselectList方法传入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();  // 总页数

三、核心差异对比

维度RowBoundsPageHelper
分页方式内存分页(先查全部,再截取)物理分页(SQL 层面限制结果范围)
性能数据量大时性能极差性能优异(依赖数据库索引)
支持数据库所有数据库(与 SQL 无关)主流数据库(自动适配不同分页语法)
分页信息获取不支持总条数、总页数(需手动查询)自动返回总条数、总页数等完整信息
灵活性仅支持offsetlimit支持排序、复杂查询分页、嵌套查询分页
适用场景数据量极小(如几十几百条)支持大数据量查询

四、优缺点总结

1. RowBounds 的优缺点

  • 优点

    • MyBatis 原生支持,无需额外依赖。
    • 实现简单,适合快速测试或极小数据量场景。
  • 缺点

    • 性能问题:大数据量下会导致 OOM(内存溢出)。
    • 功能缺失:无法获取总条数、总页数,分页逻辑需手动实现。
    • 不适合生产环境。

2. PageHelper 的优缺点

  • 优点

    • 性能优秀:基于数据库分页,减少数据传输和内存占用。
    • 功能完善:支持总条数、总页数、排序等,满足复杂分页需求。
    • 易用性高:一行代码开启分页,对原有代码侵入性极低。
    • 兼容性好:自动适配 MySQL、Oracle、SQL Server 等主流数据库。
  • 缺点

    • 需要引入第三方依赖。
    • 对复杂 SQL(如多表关联、子查询)的分页支持需注意 SQL 写法(避免拦截失效)。

五、使用建议

  1. 优先选择 PageHelper
    几乎所有生产环境都应使用 PageHelper,尤其是数据量超过 1000 条的场景。其物理分页机制能显著提升性能,且功能完备。

  2. 谨慎使用 RowBounds
    仅推荐在数据量极小(如配置表、字典表,数据量 < 1000 条)且无需分页信息的场景下使用,禁止在生产环境的大数据量查询中使用。

  3. PageHelper 使用注意事项

    • PageHelper.startPage()需在查询方法前调用,且只对后续第一个查询有效。
    • 复杂 SQL 分页时,建议通过PageHelper.offsetPage(offset, limit)手动指定偏移量和条数。
    • 避免在事务中嵌套使用分页(可能导致分页拦截失效)。

总结

RowBounds 作为 MyBatis 的原生分页方式,仅适合简单测试或极小数据量场景;而 PageHelper 通过物理分页机制,在性能、功能、易用性上全面优于 RowBounds,是生产环境的首选。实际开发中,应根据数据量和业务需求选择合适的分页方案,优先推荐 PageHelper。