前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java|PageHelper 怎么自作主张帮我分页?

Java|PageHelper 怎么自作主张帮我分页?

作者头像
mzlogin
发布2024-05-21 20:40:33
880
发布2024-05-21 20:40:33
举报
文章被收录于专栏:闷骚的程序员闷骚的程序员

开局上来,我们先看看问题场景的示例代码:

代码语言:javascript
复制
public Page<Xxx> queryXxxList(XxxPageReq req) {

    // some code here

    // 查询一,得到一个结果集,作为查询二的条件
    List<Long> fkIdList = xxxMapper.queryFkIdList(req);
    req.setFkIdList(idList);

    PageHelper.startPage(req.getPageNum(), req.getPageSize());

    // 查询二
    List<Xxx> data = xxxMapper.queryXxxList(req);

    // some code here

}

预期 的逻辑是:查询一不分页,得到一个结果集,作为查询二的条件,查询二分页。

实际 的现象是:查询一被自动添加了 limit,最多只能查询到 10 条数据(示例 req 里的 pageSize 传的 10),导致查询二的查询条件不正确。

分析

初遇到这个问题时,一脸黑人问号,冷静下来后,分析了以下几种可能性,但都一一排除了。

  • 调用当前方法的线程里,已经有其它地方先调用了 PageHelper.startPage(),导致当前方法里的查询一也被分页了;
  • 调用当前方法的线程,上一次调度时设置的分页参数没有被清理;
  • 无厘头的猜想:当前方法是不是在一个大的事务里,而 PageHelper 有什么特殊处理,导致一个事务里的查询都会被分页?

最后通过在 PageInterceptor 里下断点发现了问题所在:

代码语言:javascript
复制
@Override
public Object intercept(Invocation invocation) throws Throwable {
    // some code here 

    //调用方法判断是否需要进行分页,如果不需要,直接返回结果
    if (!dialect.skip(ms, parameter, rowBounds)) {
        // 自动 count 和 分页查询处理
    } else {
        // 跳过 count 和 分页查询处理
    }
    // some code here
}

单步跟进 dialect.skip 方法,关键逻辑在 PageParams.getPage 方法里面:

代码语言:javascript
复制
public Page getPage(Object parameterObject, RowBounds rowBounds) {
    Page page = PageHelper.getLocalPage();
    if (page == null) {
        if (rowBounds != RowBounds.DEFAULT) {
            if (offsetAsPageNum) {
                page = new Page(rowBounds.getOffset(), rowBounds.getLimit(), rowBoundsWithCount);
            } else {
                page = new Page(new int[]{rowBounds.getOffset(), rowBounds.getLimit()}, rowBoundsWithCount);
                //offsetAsPageNum=false的时候,由于PageNum问题,不能使用reasonable,这里会强制为false
                page.setReasonable(false);
            }
        } else if(supportMethodsArguments){
            // 注意这里,我们的查询一进了这个分支
            try {
                page = PageObjectUtil.getPageFromObject(parameterObject, false);
            } catch (Exception e) {
                return null;
            }
        }
        if(page == null){
            return null;
        }
        PageHelper.setLocalPage(page);
    }
    // some code here
}

可以看到,除了显式地提前调用 PageHelper.startPage、传递 rowBounds 参数进行分页外,还有一个 else if(supportMethodsArguments) 的分支,会从传递给查询的参数里尝试读取 pageNumpageSize 字段的值作为分页参数。

随后我查阅了 PageHelper 的官方文档,果然找到了相关的说明:

supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值 false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

那么,为什么我们项目里的 supportMethodsArguments 会为 true 呢?在代码里没有搜索到,最终在 Apollo 配置中心找到了 pagehelper.supportMethodsArguments = true

破案了。

解决

找到问题就好解决了。因为将 pagehelper.supportMethodsArguments = true 这个配置去掉影响太大不可控,所以此处只是将查询一的参数去掉分页字段即可。

修改后:

代码语言:javascript
复制
public Page<Xxx> queryXxxList(XxxPageReq req) {

    // some code here

    // 查询一,得到一个结果集,作为查询二的条件
    // XxxNoPageReq 与 XxxPageReq 里的字段一样,除了没有 pageSize 和 pageNum
    XxxNoPageReq noPageReq = new XxxNoPageReq();
    BeanUtils.copyProperties(req, noPageReq);
    List<Long> fkIdList = xxxMapper.queryFkIdList(noPageReq);

    // some code here

}

小结

修完老代码里的这个问题,我无奈地笑了。真是前人挖坑,后人被坑啊……

开个玩笑。

这严格来说,其实并不能算一个问题,包括解决它需要走的那些弯路,都只能归咎于对 PageHelper 的用法,以及项目的配置,了解不完全。

码途漫漫,上下求索。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024/05/20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分析
  • 解决
  • 小结
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档