在 MyBatis 中,实现分页主要有以下几种常见方式:
- 使用
LIMIT+OFFSET分页(适用于 MySQL、PostgreSQL) - 使用
RowBounds分页(MyBatis 自带) - 使用分页插件(如
PageHelper) - 通过存储过程或其他数据库特性分页(如 Oracle 的
ROWNUM、ROW_NUMBER())
✅ 1. 使用 LIMIT + OFFSET 方式(推荐)
LIMIT和OFFSET是 MySQL、PostgreSQL 等数据库提供的标准分页方式。LIMIT表示返回多少条记录。OFFSET表示跳过多少条记录。
📝 示例 1:使用 LIMIT + OFFSET 直接分页
<select id="getUsersByPage" resultType="User">
SELECT * FROM user
ORDER BY id
LIMIT #{pageSize} OFFSET #{offset}
</select>
Java 代码:
public List<User> getUsersByPage(int pageNum, int pageSize) {
int offset = (pageNum - 1) * pageSize;
return userMapper.getUsersByPage(pageSize, offset);
}
完整 Mapper 接口:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user ORDER BY id LIMIT #{pageSize} OFFSET #{offset}")
List<User> getUsersByPage(@Param("pageSize") int pageSize, @Param("offset") int offset);
}
生成的 SQL 语句:
- 查询第
2页,每页10条:
SELECT * FROM user ORDER BY id LIMIT 10 OFFSET 10;
解释:
✅ LIMIT 10 → 返回 10 条记录
✅ OFFSET 10 → 跳过前 10 条记录
✅ 2. 使用 RowBounds 方式(MyBatis 自带)
RowBounds是 MyBatis 内置的分页对象。- MyBatis 在查询结果返回后再进行分页。
- 由于是在内存中分页,不推荐在数据量很大时使用。
📝 示例 2:使用 RowBounds 分页
<select id="getUsers" resultType="User">
SELECT * FROM user ORDER BY id
</select>
Java 代码:
public List<User> getUsersByRowBounds(int pageNum, int pageSize) {
int offset = (pageNum - 1) * pageSize;
RowBounds rowBounds = new RowBounds(offset, pageSize);
return userMapper.getUsersByRowBounds(rowBounds);
}
完整 Mapper 接口:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user ORDER BY id")
List<User> getUsersByRowBounds(RowBounds rowBounds);
}
生成的 SQL 语句:
- MyBatis 会生成完整的 SQL 语句并在内存中分页:
SELECT * FROM user ORDER BY id;
解释:
✅ RowBounds 在 MyBatis 层进行分页,效率低
✅ 适合小数据量
✅ 3. 使用分页插件(推荐)
- 第三方分页插件(如
PageHelper)是最常用的分页方式。 PageHelper在执行 SQL 前自动修改 SQL 语句,直接在数据库中进行分页,性能高。- 兼容 MySQL、PostgreSQL、Oracle、SQL Server 等常见数据库。
引入 Maven 依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
📝 示例 3:使用 PageHelper 进行分页
<select id="getUsersByPage" resultType="User">
SELECT * FROM user ORDER BY id
</select>
Java 代码:
public List<User> getUsersByPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
return userMapper.getUsersByPage();
}
完整 Mapper 接口:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user ORDER BY id")
List<User> getUsersByPage();
}
生成的 SQL 语句:
SELECT * FROM user ORDER BY id LIMIT 10 OFFSET 10;
PageHelper 自动生成的分页查询:
✅ PageHelper.startPage(pageNum, pageSize) 会在执行 SQL 之前,自动修改 SQL 语句
✅ 在 SQL 级别分页,性能高
引入 PageHelper 配置(MyBatis 配置):
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30
结果封装为 PageInfo(可分页返回):
PageInfo<User> pageInfo = new PageInfo<>(userMapper.getUsersByPage());
System.out.println("总页数:" + pageInfo.getPages());
System.out.println("当前页:" + pageInfo.getPageNum());
System.out.println("总记录数:" + pageInfo.getTotal());
System.out.println("结果集:" + pageInfo.getList());
✅ 4. 使用 Oracle 的 ROWNUM 方式分页
Oracle 中不支持 LIMIT 和 OFFSET,需要通过 ROWNUM 或 ROW_NUMBER() 进行分页。
📝 示例 4:使用 Oracle 的 ROWNUM 进行分页
<select id="getUsersByPage" resultType="User">
SELECT *
FROM (
SELECT a.*, ROWNUM rnum
FROM (
SELECT * FROM user ORDER BY id
) a
WHERE ROWNUM <= #{offset} + #{pageSize}
)
WHERE rnum > #{offset}
</select>
Java 代码:
public List<User> getUsersByPage(int pageNum, int pageSize) {
int offset = (pageNum - 1) * pageSize;
return userMapper.getUsersByPage(offset, pageSize);
}
生成的 SQL 语句:
SELECT *
FROM (
SELECT a.*, ROWNUM rnum
FROM (
SELECT * FROM user ORDER BY id
) a
WHERE ROWNUM <= 20
)
WHERE rnum > 10;
🚀 5. 性能对比
| 方式 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
LIMIT + OFFSET | MySQL、PostgreSQL | 性能好,数据库级别分页 | 大数据时性能下降 |
RowBounds | 小数据量 | 直接在内存中分页 | 数据量大时内存占用高 |
PageHelper | 通用 | 直接生成分页 SQL,性能好 | 需引入外部库 |
ROWNUM | Oracle | 适合 Oracle | 语法复杂,兼容性差 |
🎯 最佳实践
✅ 小数据量 → RowBounds
✅ 中等数据量 → LIMIT + OFFSET
✅ 大数据量 → PageHelper
✅ Oracle → ROWNUM or ROW_NUMBER()
🎉 总结:
- 小数据量 → 用
RowBounds处理 - 中等数据量 → 用
LIMIT + OFFSET - 大数据量 → 用
PageHelper插件 - Oracle → 用
ROWNUM或ROW_NUMBER()
👉 推荐使用 PageHelper,性能和兼容性更好! 😎