什么是 RowBounds?
RowBounds 是 MyBatis 提供的逻辑分页工具类,用于控制查询结果的 偏移量(offset) 和 每页条数(limit)。
List<User> users = userMapper.selectAll(new RowBounds(10, 20));上面的例子表示:从第 11 条记录开始,取 20 条。
RowBounds 的类定义简化如下:
public class RowBounds {
public static final int NO_ROW_OFFSET = 0;
public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
private int offset;
private int limit;
public RowBounds(int offset, int limit) {
this.offset = offset;
this.limit = limit;
}
}RowBounds 的实现原理
关键点:RowBounds 不会修改 SQL,而是在内存中对查询结果进行截取。
也就是说:
MyBatis 会先执行 SQL 查询,将所有符合条件的结果从数据库中取出。
然后在内存中,根据
offset和limit进行分页处理。
示意逻辑如下:
List<User> allUsers = queryAllUsersFromDB(); // 查询所有结果
List<User> pageUsers = allUsers.subList(offset, offset + limit); // 截取分页
因此,RowBounds 是内存分页,而不是数据库层面的分页。
RowBounds 的优缺点
优点
简单易用,无需改动 SQL;
对小数据量或缓存数据分页场景适用。
缺点
无论查询第几页,都会把所有结果加载到内存,性能差;
大数据量时,容易造成内存压力;
数据库层索引无法充分利用。
如何实现高性能分页?
MyBatis 官方推荐在大数据量场景下,使用物理分页,即在 SQL 层面做分页。
1. 使用 PageHelper 插件
PageHelper.startPage(2, 10); // 第2页,每页10条
List<User> users = userMapper.selectAll();
生成 SQL:
SELECT * FROM user LIMIT 10 OFFSET 10;
2. 使用 MyBatis Plus 分页
IPage<User> page = new Page<>(2, 10);
IPage<User> result = userMapper.selectPage(page, null);
物理分页,性能更高。
源码层面的 RowBounds
在 MyBatis 的执行流程中:
Executor执行查询;检测是否传入
RowBounds;查询完成后,在内存中处理结果集,跳过前
offset条,只收集limit条。
源码片段(简化):
while (rs.next()) {
if (rowBounds.getOffset() > count) continue;
if (collected >= rowBounds.getLimit()) break;
resultHandler.handleResult(row);
}
总结
分页方式 | 实现层级 | 是否改 SQL | 性能 | 推荐使用 |
|---|---|---|---|---|
RowBounds | 内存层 | ❌ 否 | ❌ 差 | ❌ 不推荐 |
PageHelper | SQL 层拦截 | ✅ 是 | ✅ 好 | ✅ 推荐 |
MyBatis Plus 分页 | SQL 层拦截 | ✅ 是 | ✅ 好 | ✅ 推荐 |
一句话总结:
RowBounds是 MyBatis 的逻辑分页工具,只在内存中截取结果,性能较差;大数据量场景应使用分页插件实现数据库层分页。
评论区