Spring Boot项目里PageHelper分页失效?别慌,这5个坑我帮你踩过了
Spring Boot项目中PageHelper分页失效的五大陷阱与实战解决方案
最近在重构一个老项目时,我又一次遇到了PageHelper分页失效的问题。这已经是第三次了,每次都能让我在调试时抓狂半小时。PageHelper作为MyBatis最流行的分页插件,用起来简单,但一旦出问题,排查起来却让人头疼。本文将分享我在实际项目中遇到的五种典型分页失效场景,以及如何快速定位和解决这些问题。
1. 依赖版本冲突:最隐蔽的坑
很多开发者在使用PageHelper时,第一个踩到的坑就是依赖版本不匹配。Spring Boot项目中有多个PageHelper相关的依赖,如果版本不一致,分页功能可能完全失效。
<!-- 错误示例:版本混用 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
推荐做法 是使用starter依赖,它会自动管理所有相关依赖的版本:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
如果必须单独引入,请确保所有PageHelper相关依赖版本一致。我曾经遇到过一个项目,pagehelper-core和pagehelper-spring-boot版本不一致,导致分页拦截器根本没有被注册。
2. 配置顺序问题:分页拦截器的正确打开方式
PageHelper的工作原理是通过MyBatis的拦截器机制实现的。如果配置不当,拦截器可能无法正确拦截SQL语句。
在Spring Boot中,有几种常见的配置方式:
- application.yml配置 (推荐):
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
- Java Config方式 :
@Bean
public PageInterceptor pageInterceptor() {
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
properties.setProperty("helperDialect", "mysql");
properties.setProperty("reasonable", "true");
pageInterceptor.setProperties(properties);
return pageInterceptor;
}
关键点 :确保配置在SqlSessionFactory创建之前完成。我曾经在一个多数据源项目中,因为配置顺序问题,导致主数据源的分页失效。
3. 多数据源环境下的特殊处理
在多数据源项目中,PageHelper的配置需要特别注意。每个SqlSessionFactory都需要单独配置分页拦截器。
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
// 添加PageInterceptor
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
properties.setProperty("helperDialect", "mysql");
factoryBean.setPlugins(pageInterceptor);
return factoryBean.getObject();
}
常见错误 :
- 只在主数据源配置了分页拦截器
- 不同数据源使用了不同的方言配置
- 拦截器实例被多个SqlSessionFactory共享
4. 分页方法调用时机:PageHelper.startPage的陷阱
PageHelper.startPage()方法必须在查询方法调用之前执行,而且只对紧随其后的第一个查询有效。
// 正确用法
public PageInfo<User> getUsers(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAll();
return new PageInfo<>(users);
}
// 错误用法1:startPage在查询之后
public PageInfo<User> getUsersWrong1(int pageNum, int pageSize) {
List<User> users = userMapper.selectAll();
PageHelper.startPage(pageNum, pageSize); // 太晚了!
return new PageInfo<>(users);
}
// 错误用法2:多个查询
public PageInfo<User> getUsersWrong2(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users1 = userMapper.selectAll(); // 这个会被分页
List<User> users2 = userMapper.selectActive(); // 这个不会
return new PageInfo<>(users2); // 返回的是未分页的结果
}
实战技巧 :在Service方法的最开始调用startPage,并且确保方法中只有一个查询。
5. SQL语句与分页的兼容性问题
不是所有的SQL语句都能很好地与PageHelper配合工作。以下是一些需要注意的情况:
- UNION查询 :PageHelper对UNION查询的支持有限,可能需要手动处理分页
- 嵌套查询 :复杂的嵌套查询可能导致分页计算错误
- 存储过程 :PageHelper无法拦截存储过程调用
- 手动分页参数 :SQL中已经包含LIMIT语句
解决方案 :
- 对于复杂查询,考虑拆分为多个简单查询
- 使用PageHelper的
PageMethod进行手动分页控制 - 对于特殊场景,可能需要放弃PageHelper,使用MyBatis提供的RowBounds
// 手动分页示例
public List<User> getUsersManual(int pageNum, int pageSize) {
Page<User> page = PageMethod.startPage(pageNum, pageSize);
userMapper.selectAll();
return page;
}
调试技巧与最佳实践
当分页失效时,可以按照以下步骤排查:
- 检查是否真的调用了PageHelper.startPage()
- 查看MyBatis日志,确认是否生成了分页SQL
- 检查拦截器是否被正确注册
- 确认没有其他拦截器干扰PageHelper的工作
最佳实践 :
- 统一使用PageHelper的starter依赖
- 保持配置简单,避免过度定制
- 为分页方法添加清晰的文档注释
- 编写单元测试验证分页行为
@Test
public void testPagination() {
// 第一页,每页10条
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
assertEquals(10, users.size());
assertTrue(pageInfo.isIsFirstPage());
assertFalse(pageInfo.isIsLastPage());
}
分页是Web开发中最常见的功能之一,也是容易出错的环节。理解PageHelper的工作原理,避免这些常见陷阱,可以节省大量调试时间。在实际项目中,我建议建立一个分页工具类,封装常见的分页操作,减少重复代码和出错机会。
更多推荐


所有评论(0)