前提:为适配项目发展,完善项目生态,并贴合微服务的环境,最近在对项目进行升级改造,有SpringMVC架构升级为SpringBoot项目,升级过程还比较顺利,并完成大部分功能测试和验证。
突然产品说系统管理功能中用户的编辑功能突然失效,经过排查代码发现在查询用户角色的接口中复用的是角色管理分页查询的接口,并做了查询总数判断,由于此处未进行分页参数设置,导致查询总数的count=-1,导致数据加载异常。
回忆下针对pagehelper适配过程,之前使用时4版本,由于springboot使用了2版本,因此升级了pagehelper5,之前4版本无问题,其中代码业务逻辑是:
int pageNum = entity.getPage() == null ? 0 : entity.getPage().intValue(); int pageSize = entity.getLimit() == null ? 0 : entity.getLimit().intValue(); boolean flag = (pageNum == 0 && pageSize == 0) ? false : true; Page<E> page = PageHelper.startPage(pageNum, pageSize, flag);
很明显4版本中count标识位设置为false可以正常查询数据总数,5版本不行,通过设置为true时,验证后才能通过page.getTotal()获取分页查询的总数。
原因分析:
debug源码发现,在PageInterceptor(参考Mybatis执行拦截器Interceptor)中在执行:
if (this.dialect.beforeCount(ms, parameter, rowBounds)) {//-----此函判断为false,未执行查询总数的操作 String countMsId = msId + this.countSuffix; MappedStatement countMs = this.getExistedMappedStatement(configuration, countMsId); Long count; if (countMs != null) { count = this.executeManualCount(executor, countMs, parameter, boundSql, resultHandler); } else { countMs = (MappedStatement)this.msCountMap.get(countMsId); if (countMs == null) { countMs = MSUtils.newCountMappedStatement(ms, countMsId); this.msCountMap.put(countMsId, countMs); } count = this.executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler); } if (!this.dialect.afterCount(count, parameter, rowBounds)) { Object var24 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds); return var24; } }
此时继续追踪:
private Dialect dialect; private String default_dialect_class = "com.github.pagehelper.PageHelper";
在PageHelper中:beforeCount执行的三个参数:
ms:具体的要执行的mapper.xml文件
parameter:执行mapper.xml查询时候传递过去的参数
rowBounds:分页参数:此时为offset:0,limit:2147483647
执行的函数为:com.github.pagehelper.dialect.AbstractHelperDialect
看这段业务逻辑:
public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { Page page = this.getLocalPage(); return !page.isOrderByOnly() && page.isCount(); }
其中:page.isOrderByOnly()是false,我们没有设置,此时我们逻辑中page.isCount()设置为false,故此时不在去执行查询总数的操作,如果我们想获取总数,无论是否分页我们在创建Page对象时一律设置为true即可。