MyBatis的分页实现主要有以下几种方式:
1. 逻辑分页(RowBounds)
在MyBatis核心包中提供,但存在性能问题:
// 使用RowBounds进行内存分页
List<User> users = sqlSession.selectList(
"com.example.mapper.UserMapper.selectUsers",
null,
new RowBounds(0, 10) // offset, limit
);
缺点:实际查询所有数据到内存后再分页,大数据量时性能差
2. 物理分页(原生SQL)
手动在SQL中编写分页语句:
MySQL
<select id="selectByPage" resultType="User">
SELECT * FROM user
LIMIT #{offset}, #{pageSize}
</select>
Oracle
<select id="selectByPage" resultType="User">
SELECT * FROM (
SELECT t.*, ROWNUM rn FROM (
SELECT * FROM user ORDER BY id
) t WHERE ROWNUM <= #{end}
) WHERE rn >= #{start}
</select>
3. 分页插件(推荐)
PageHelper(最常用)
<!-- 1. 添加依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
// 2. 使用示例
PageHelper.startPage(1, 10); // 第1页,每页10条
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
// 获取分页信息
pageInfo.getTotal(); // 总记录数
pageInfo.getPages(); // 总页数
pageInfo.getList(); // 当前页数据
MyBatis-Plus分页
// 1. 配置分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
// 2. 使用
Page<User> page = new Page<>(1, 10);
IPage<User> userPage = userMapper.selectPage(page, null);
userPage.getTotal(); // 总记录数
userPage.getRecords(); // 分页数据
4. 自定义分页拦截器
可以自己实现Interceptor接口:
@Intercepts(@Signature(type = StatementHandler.class,
method = "prepare", args = {Connection.class, Integer.class}))
public class PageInterceptor implements Interceptor {
// 实现分页逻辑
// 1. 解析分页参数
// 2. 重写SQL,添加分页语句
// 3. 查询总数
}
5. 参数分页
通过Map或PageParam对象传递参数:
public interface UserMapper {
List<User> selectByPage(@Param("offset") int offset,
@Param("pageSize") int pageSize);
}
<select id="selectByPage" resultType="User">
SELECT * FROM user
<if test="offset != null and pageSize != null">
LIMIT #{offset}, #{pageSize}
</if>
</select>
最佳实践建议
- 中小型项目:推荐使用PageHelper,配置简单,功能丰富
- 使用MyBatis-Plus的项目:直接使用其内置分页功能
- 需要自定义逻辑:可考虑实现自定义拦截器
- 性能要求极高:手动编写优化SQL,使用数据库特定语法
性能对比
| 分页方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| RowBounds | 简单易用 | 内存分页,性能差 | 小数据量测试 |
| 原生SQL | 性能最好 | SQL不通用,维护难 | 对性能要求极高 |
| PageHelper | 功能全面,易用 | 增加依赖 | 大多数业务场景 |
| MyBatis-Plus | 无缝集成 | 需全套使用MP | 使用MP的项目 |
注意事项:
- 分页时要考虑排序字段的索引优化
- 深度分页(如第1000页)建议使用游标或搜索优化
- 分布式环境下注意分页一致性