别再踩坑了!手把手教你配置MyBatis-Plus 3.5+的分页插件PaginationInnerInterceptor
MyBatis-Plus 3.5+分页插件全指南:从原理到避坑实战
最近在技术社区看到不少开发者反馈MyBatis-Plus升级到3.5+版本后分页功能突然失效,这其实是框架架构调整带来的配置变化。作为深度使用MyBatis-Plus的开发者,我完整经历了从旧版到新版的迁移过程,今天就把这些实战经验系统梳理出来。
1. 为什么你的分页突然失效了?
MyBatis-Plus在3.4/3.5版本进行了架构重构,最显著的变化就是将原先独立的插件体系改为拦截器链模式。这意味着:
- 旧版直接注册
PaginationInterceptor的方式不再适用 - 新版必须通过
MybatisPlusInterceptor统一管理所有插件 - 分页实现类更名为
PaginationInnerInterceptor
典型报错表现:
// 控制台无分页SQL生成 SELECT * FROM user LIMIT ? // 返回结果未分页,获取到全部数据常见配置误区包括:
- 直接复制旧版配置代码未做适配
- 忘记将分页插件添加到拦截器链
- 错误地同时注册了新旧两种插件
2. 新版分页插件核心配置详解
2.1 基础Java配置方案
以下是经过生产验证的标准配置模板:
@Configuration @MapperScan("com.yourpackage.mapper") public class MybatisPlusConfig { /** * 新版分页插件 (3.5+) */ @Bean public PaginationInnerInterceptor paginationInnerInterceptor() { PaginationInnerInterceptor interceptor = new PaginationInnerInterceptor(); // 数据库类型建议显式声明 interceptor.setDbType(DbType.MYSQL); // 单页最大记录数(-1表示不限制) interceptor.setMaxLimit(1000L); // 开启count查询优化 interceptor.setOptimizeJoin(true); return interceptor; } /** * 必须将分页插件添加到拦截器链 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(paginationInnerInterceptor()); return interceptor; } }关键参数说明:
| 参数 | 类型 | 默认值 | 建议设置 |
|---|---|---|---|
| dbType | DbType | 自动检测 | 生产环境建议显式指定 |
| maxLimit | Long | 500 | 根据业务调整,-1表示不限制 |
| optimizeJoin | Boolean | false | 关联查询时建议开启 |
2.2 XML配置方案(适合传统项目)
对于仍在使用Spring XML配置的项目:
<bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"> <property name="dbType" value="MYSQL"/> </bean> <bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"> <property name="interceptors"> <list> <ref bean="paginationInnerInterceptor"/> </list> </property> </bean>3. 高级配置与性能优化
3.1 多数据源分页适配
当项目使用多数据源时,需要针对不同数据库配置对应的分页插件:
@Bean @ConditionalOnProperty(prefix = "spring.datasource", name = "primary") public PaginationInnerInterceptor mysqlPagination() { PaginationInnerInterceptor interceptor = new PaginationInnerInterceptor(DbType.MYSQL); interceptor.setOverflow(true); // 超出页数返回第一页 return interceptor; } @Bean @ConditionalOnProperty(prefix = "spring.datasource", name = "secondary") public PaginationInnerInterceptor oraclePagination() { return new PaginationInnerInterceptor(DbType.ORACLE); }3.2 分页性能优化技巧
- Count查询优化:
// 对于单表查询可以关闭count优化 interceptor.setOptimizeJoin(false); // 复杂查询建议使用自定义count语句 @Select("SELECT * FROM user WHERE ...") @Select("SELECT COUNT(1) FROM user WHERE ...") Page<User> selectPage(Page<?> page, @Param("param") QueryParam param);- 页面溢出处理:
// 请求页码超过总页数时是否回到首页 interceptor.setOverflow(false); // 配合前端处理 if (page.getCurrent() > page.getPages()) { throw new BusinessException("页码超出范围"); }4. 验证与调试指南
4.1 配置有效性检查
通过以下步骤确认分页是否生效:
- 在Controller中添加测试接口:
@GetMapping("/testPage") public Page<User> testPage(@RequestParam(defaultValue = "1") int current) { return userService.page(new Page<>(current, 10)); }- 观察控制台SQL输出:
-- 应该看到LIMIT子句 SELECT * FROM user LIMIT 10 -- 以及自动生成的count查询 SELECT COUNT(1) FROM user4.2 常见问题排查
问题现象:分页查询返回全部记录
- 检查拦截器是否注册到Spring容器
- 确认
MybatisPlusInterceptor包含分页插件
问题现象:count查询报错
- 复杂SQL可能需要关闭
optimizeJoin - 考虑使用自定义count语句
问题现象:分页参数未生效
- 检查Page参数是否正确传递
- 确认没有其他拦截器修改了SQL
5. 最佳实践与避坑指南
在实际项目迭代中,我们总结了这些经验:
版本兼容建议:
- 3.5.0-3.5.3存在一些边界case问题
- 推荐使用3.5.3+稳定版本
事务注意事项:
// 分页查询建议放在只读事务中 @Transactional(readOnly = true) public Page<User> queryPage(PageQuery query) { // ... }- 前端协作规范:
// 推荐分页响应格式 { "records": [...], "total": 100, "size": 10, "current": 1, "pages": 10 }- 特殊场景处理:
// 手动分页示例 IPage<User> manualPage = new Page<>(1, 10); List<User> records = userMapper.selectByCustomQuery(manualPage); manualPage.setRecords(records); return manualPage;最近在金融项目中迁移到MyBatis-Plus 3.5.4时,发现当使用Oracle数据库时如果不显式设置dbType会导致分页语法错误。这个坑花了两小时才排查出来,所以特别提醒大家多数据源环境下一定要明确指定数据库类型。
