tk-mybatis 搭配分页插件 pagehelper 使用遇到的问题
缘起
在项目增加新的功能模块的时候,对于后端即接口,根据数据库表结构一顿闷头敲代码。之后对接接口的时候,前端反馈了一个比较奇怪的问题:列表分页不管用,下拉刷新更新下一页内容,明明应该没有下一页数据,但结果却正常返回了最后一页的数据。
使用 postman 测试确认了问题:如果是访问最大页数之前的分页内容,数据正常返回;如果当前页超过了最大页数,数据返回最后一页的数据。
分页调用示例代码:
PageHelper.startPage(page, size);
List<User> userList = userMapper.selectUserList();
return PageInfo.of(userList);
调用其他的分页列表接口,发现这并不是调用错误。本地调试确认传递进入的参数没有问题,但日志里显示的分页 sql 查询的是有数据的最后一页,返回的分页信息里 pageNum
显示也是最后一页的页码。似乎 pagehelper 对传入的参数做了一个校验修正。
当然这并不影响正常的使用,后台是显示所有的可用页码,并且返回的分页信息里也有 hasNextPage
是否有下一页字段可供判断,所以前端可以处理好这个问题。但还是好奇到底是哪里出现了问题。
研究过程
查看引入的依赖,主要是 tk-mybatis(作者更愿意叫 MyBatis 通用 Mapper,属于 MyBatis 的扩展、增强框架)和 pagehelper。因为对两个依赖不太熟悉,不确定是否是版本的问题,所以决定将两个依赖放到新建的测试项目中本地调试看看。
为控制变量,选择与原项目相同版本的依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>xxx</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>xxx</version>
</dependency>
复制原项目中针对 mybatis、mapper、pagehelper 的一些配置项:
#mybatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.seasidecrab.tkmybatis
mapper-locations: classpath:mapper/**/*Mapper.xml
mybatis.configuration.map-underscore-to-camel-case: true
mybatis.configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 加载全局的配置文件
config-Location: classpath:mybatis/mybatis-config.xml
mapper:
not-empty: true
identity: MYSQL
# PageHelper分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
创建好相关的 service、mapper 类与 xml 文件之后,按照上面的 分页调用示例代码
进行测试。具体的操作方法参考pagehelper 官方文档。
测试复现了返回页数据重复问题:
接下来是控制变量,对比测试:
- 将 mapper-spring-boot-starter 升级到最新 4.2.3,没有变化
- 将 pagehelper-spring-boot-starter 升级到最新 2.1.0,没有变化
- 将 mapper-spring-boot-starter 替换成 mybatis-spring-boot-starter 最新版 3.0.3,修改 mapper 引入方式以及使用了 tk 的注解,报错:
java.lang.UnsupportedClassVersionError: org/mybatis/spring/boot/autoconfigure/MybatisLanguageDriverAutoConfiguration has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
,根据意思猜测是 java 1.8 版本有点低 - 将 mapper-spring-boot-starter 替换成 mybatis-spring-boot-starter 次新版 2.3.2,没报错,但也没有变化
- 感觉不对头,方向似乎搞错了,应该调整 pagehelper 而非 mybatis。将 pagehelper-spring-boot-starter 替换成原初的 pagehelper 最新版 6.1.0,按照 pagehelper 官方文档在 MyBatis 配置 xml 中配置拦截器插件,成功了。
成功后的返回(也是正确的返回):
跟进解决
pagehelper-spring-boot-starter
是对于 pagehelper
的一个包装依赖,正常来说,不会存在这样的 bug。到 github 的 issues 中翻了一下,找到了一个合理的解答:pageNum超出totalPages,分页总是返回最后一页的数据 #157。贡献者回复:
查看分页合理化参数,设置false即可。
从 pagehelper 官方文档 中找到这个配置参数说明:
reasonable
:分页合理化参数,默认值为false
。当该参数设置为true
时,pageNum<=0
时会查询第一页,pageNum>pages
(超过总数时),会查询最后一页。默认false
时,直接根据参数进行查询。
检查前面的配置项,确实 reasonable: true
。好嘛,原来是这个配置在搞事情,默认为 false,即不配置就不会有问题。在 pagehelper
没有生效,所以就没有问题。
下次遇到问题,不妨先去 github 上翻一翻 issues,说不定就有解决方法。