Cannot invoke "com.github.pagehelper.Page.getPageNum()" because "page" is null
时间: 2025-06-04 21:42:31 浏览: 17
<think>好的,我现在需要解决用户的问题:用户在使用MyBatis PageHelper时遇到了“Cannot invoke 'com.github.pagehelper.Page.getPageNum()' because 'page' is null”的错误。首先,我要理解这个错误的原因。
用户之前的对话中提到过Page类需要正确引入依赖,所以用户可能已经解决了依赖问题。现在的问题在于page对象为null,导致调用getPageNum()方法时出现空指针异常。这说明虽然用户可能正确导入了Page类,但分页查询过程中出现了问题,导致PageHelper没有正确创建Page实例。
接下来,我需要考虑可能的原因。首先,用户是否正确调用了PageHelper.startPage()方法?如果这个方法没有被正确调用,或者在查询之后才调用,那么PageHelper的本地线程变量可能没有被设置,导致getPage()返回null。此外,可能存在线程问题,比如在异步或子线程中调用分页方法,导致无法获取到Page实例。另外,用户可能在两次分页查询之间没有清理线程变量,或者分页逻辑中有异常导致线程变量未被正确设置。
然后,我需要考虑解决方案。首先应该检查startPage()的调用位置是否正确,确保在查询执行之前调用。然后,检查是否在同一个线程中执行查询,避免异步问题。另外,确保分页逻辑中没有异常中断导致PageHelper未正确初始化。最后,确认是否正确使用了PageHelper的API,比如是否正确获取了Page对象。
用户可能的深层需求是希望分页功能正常工作,而不仅仅是解决这个错误。他们可能对PageHelper的工作机制不太熟悉,需要更详细的步骤指导。因此,除了解决当前的错误,可能还需要提供示例代码和常见问题的解决方法,帮助他们彻底理解分页的正确用法,避免未来出现类似问题。
总结,我需要分步骤解释错误原因,并提供详细的解决方案,包括代码示例和注意事项,确保用户能够一步步排查问题,并正确使用PageHelper的分页功能。</think>出现 `Cannot invoke "Page.getPageNum()" because "page" is null` 错误,是因为 **分页逻辑未正确触发**,导致 `PageHelper` 未生成分页对象 `Page`。以下是具体原因和解决方案:
---
### **原因分析**
1. **`PageHelper.startPage()` 未被调用或调用位置错误**
分页逻辑需要在查询数据库 **之前** 调用 `PageHelper.startPage()`,否则后续无法获取 `Page` 对象。
2. **线程上下文问题**
`PageHelper` 的分页参数存储在线程本地变量(`ThreadLocal`)中,如果在异步线程或多次分页查询后未清理,会导致分页参数丢失。
3. **分页逻辑被异常中断**
如果 `startPage()` 和查询之间抛出了异常,可能导致分页参数未正确绑定到结果。
---
### **解决方案**
#### 1. 确保 `PageHelper.startPage()` 在查询前调用
```java
// 正确写法:先调用 startPage,再执行查询
PageHelper.startPage(pageNum, pageSize); // 关键!
List<User> userList = userMapper.selectAllUsers();
// 获取分页对象(此时 page 不会为 null)
Page<User> page = (Page<User>) userList;
int currentPage = page.getPageNum(); // 安全调用
```
#### 2. 检查代码逻辑顺序
确保 **没有** 以下错误顺序:
```java
List<User> userList = userMapper.selectAllUsers(); // ❌ 先查询
PageHelper.startPage(pageNum, pageSize); // ❌ 后分页(完全无效)
```
#### 3. 处理异步线程问题
如果在子线程或异步任务中使用分页,需手动传递分页参数:
```java
// 主线程中启动分页
Page<?> page = PageHelper.startPage(1, 10);
// 异步线程中重新绑定分页参数
CompletableFuture.runAsync(() -> {
PageHelper.setPage(page);
List<User> userList = userMapper.selectAllUsers();
// ...
}).join(); // 确保异步任务完成
```
#### 4. 使用 `PageInfo` 替代直接强制转型(推荐!)
更安全的方式是通过 `PageInfo` 获取分页信息:
```java
PageHelper.startPage(pageNum, pageSize);
List<User> userList = userMapper.selectAllUsers();
// 使用 PageInfo 包装结果(无需强制转换,避免空指针)
PageInfo<User> pageInfo = new PageInfo<>(userList);
int currentPage = pageInfo.getPageNum(); // 安全获取
```
#### 5. 检查是否存在异常中断
确保 `startPage()` 和查询之间没有抛出异常:
```java
try {
PageHelper.startPage(1, 10);
List<User> userList = userMapper.selectAllUsers(); // 确保此方法无异常
Page<User> page = (Page<User>) userList;
} catch (Exception e) {
// 异常会导致分页参数未被清除,需手动清理
PageHelper.clearPage();
}
```
---
### **完整示例代码**
```java
@RequestMapping("/users")
public PageInfo<User> getUsers(@RequestParam int pageNum, @RequestParam int pageSize) {
// 1. 启动分页(必须在查询前调用!)
PageHelper.startPage(pageNum, pageSize);
// 2. 执行查询
List<User> userList = userService.getAllUsers();
// 3. 用 PageInfo 包装结果(推荐)
return new PageInfo<>(userList);
}
```
---
### **常见陷阱**
- **误用 `PageHelper` 的其他方法**:例如 `PageHelper.offsetPage()` 和 `startPage()` 混用导致冲突。
- **未清理分页参数**:多次分页查询后,调用 `PageHelper.clearPage()` 清理线程变量。
- **返回结果被过滤或二次处理**:例如对 `userList` 进行 `stream().filter()` 操作后,分页信息会丢失。
---
通过以上步骤排查,你的 `page` 对象应该不再为 `null`。如果问题依旧,可以检查 MyBatis 拦截器配置或 `PageHelper` 版本兼容性。
阅读全文
相关推荐















