PageHelper.startPage()没生效的根本原因是调用位置不当或上下文丢失,它依赖ThreadLocal传递分页参数,必须紧邻Mapper查询执行,且需确保插件注册、方言配置正确及避免事务/代理干扰。

PageHelper.startPage() 为什么没生效?
根本原因通常是 PageHelper.startPage() 调用位置不对,或者后续的 Mapper 查询不是紧跟其后执行(比如被缓存、异步、代理拦截干扰)。它依赖线程局部变量(ThreadLocal)记录分页参数,一旦中间穿插了其他数据库操作、事务切换或跨线程调用,上下文就丢了。
实操建议:
立即学习“Java免费学习笔记(深入)”;
-
PageHelper.startPage()必须在Mapper方法调用前「紧邻」执行,中间不能有其他 MyBatis 查询、Spring 事务注解触发的代理方法、日志增强等干扰 - 不要在 service 层 try-catch 后再调用 startPage —— 异常可能让后续查询跳过该行
- 如果用了 Spring 的
@Transactional,确保它不包裹在 startPage 之前(事务代理可能延迟执行,导致 PageHelper 上下文已失效) - 检查是否误用了
PageHelper.orderBy("xxx")却没配startPage,这不会自动分页
PageInfo 对象里 total=0 或 list 为空但 SQL 明明查得出数据
这不是 SQL 写错了,而是 PageInfo 包装逻辑依赖于 PageHelper 的「分页拦截器」成功拦截并重写 SQL。如果拦截失败(比如用了 selectOne、手写 RowBounds、或 XML 中用了 <select> 以外的标签),PageHelper 就不会注入 COUNT 查询,PageInfo.total 就只能靠内存计算(此时为 0)。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 只对
selectList类型的 Mapper 方法使用 PageHelper;避免对selectOne或自定义ResultHandler调用startPage - 确认 MyBatis 配置中已注册 PageHelper 插件:
<plugin interceptor="com.github.pagehelper.PageInterceptor">,且版本与 MyBatis 3.4+ 兼容 - 开启 PageHelper 的 debug 日志(
pagehelper.helperDialect=mysql+logging.level.com.github.pagehelper=DEBUG),看控制台是否打印出生成的 COUNT SQL -
PageInfo必须用new PageInfo<>(list)构造,不能直接 new 空对象再 set —— 它的total是在构造时从Page中提取的
Spring Boot 项目里 PageHelper 自动配置失效或方言识别错误
常见现象是分页 SQL 没加 LIMIT,或报错 There is no dialect instance for mysql。本质是 PageHelper 没正确读到数据库类型,或 starter 版本与 MyBatis 整合有 gap。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 优先用官方推荐的 starter:
pagehelper-spring-boot-starter(注意对应 MyBatis 版本:3.4.x 用 1.4.x,3.5.x 用 1.5.x+) - application.yml 中必须显式指定方言:
pagehelper.helper-dialect: mysql(注意是helper-dialect,不是dialect) - 如果用多数据源,PageHelper 默认只作用于第一个 SqlSessionFactory;需手动为每个
SqlSessionFactory注册PageInterceptorBean - 避免同时引入旧版
pagehelper和新版 starter,Maven 会因传递依赖冲突导致方言类加载失败
PageInfo 的 pages、navigatePages、navigatepageNums 这些字段怎么用才不翻车
这些字段不是“开箱即用”的页码导航数组,它们依赖 PageInfo 构造时传入的原始 List 是否来自 PageHelper 拦截后的分页结果。如果传的是普通 List,navigatepageNums 就是空数组,pages 永远是 1。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 务必从
PageHelper.startPage().doSelectPageInfo(() -> mapper.selectAll())或先startPage再mapper.selectXxx()得到 List,再传给new PageInfo<>(list) -
navigatePages控制页码栏显示几个数字(默认 8),但它只影响navigatepageNums数组长度,不改变pages(总页数) - 前端做分页栏时,别直接遍历
navigatepageNums—— 它可能为 null;应先判空,再用getNavigatepageNums()安全获取 -
PageInfo不支持修改后重新计算,所有字段都是构造时快照;想换页码范围,得重新查一次










