使用com.github.pagehelper插件分页、count分析

11 篇文章 0 订阅
pagehelper侵入研究

mybatis插件中有一个拦截器org.apache.ibatis.plugin.Interceptor,主要用于mybatis插件的植入。pagehelper的PageInterceptor实现了Interceptor,PageInterceptor在所有执行query操作时插入拦截。

PageInterceptor 分页器跳过分页
//调用方法判断是否需要进行分页,如果不需要,直接返回结果
if (!dialect.skip(ms, parameter, rowBounds)) {
 ...
}

public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
      if(ms.getId().endsWith(MSUtils.COUNT)){
          throw new RuntimeException("在系统中发现了多个分页插件,请检查系统配置!");
      }
      //获取分页参数成功,则分页,获取失败,则跳过分页
      Page page = pageParams.getPage(parameterObject, rowBounds);
      if (page == null) {
          return true;
      } else {
          //设置默认的 count 列
          if(StringUtil.isEmpty(page.getCountColumn())){
              page.setCountColumn(pageParams.getCountColumn());
          }
          autoDialect.initDelegateDialect(ms);
          return false;
      }
  }

从skip方法可以看出,跳过分页的重点在pageParams.getPage。

//如果当前threadlocal中有page取当前threadlocal中的page
Page page = PageHelper.getLocalPage();
        if (page == null) {
        	// 不人为修改时rowBounds = RowBounds.DEFAULT
            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);
                }
                if(rowBounds instanceof PageRowBounds){
                    PageRowBounds pageRowBounds = (PageRowBounds)rowBounds;
                    page.setCount(pageRowBounds.getCount() == null || pageRowBounds.getCount());
                }
             //如果pagehelper.supportMethodsArguments 设置为true,也就是支持接口参数来传递分页参数
            } else if(supportMethodsArguments){
                try {
                    page = PageObjectUtil.getPageFromObject(parameterObject, false);
                } catch (Exception e) {
                    return null;
                }
            }
            if(page == null){
                return null;
            }
            PageHelper.setLocalPage(page);
        }

从上面代码可以看出 如果没有修改rowBounds,并且没有设置pagehelper.supportMethodsArguments 属性为true,是不会走分页的,也就是直接skip掉了。但是通常我们希望接口来传递分页参数,会把pagehelper.supportMethodsArguments设置为true。所以会走page = PageObjectUtil.getPageFromObject(parameterObject, false)流程。

public static <T> Page<T> getPageFromObject(Object params, boolean required) {
        int pageNum;
        int pageSize;
        MetaObject paramsObject = null;
        if (params == null) {
            throw new PageException("无法获取分页查询参数!");
        }
        if (hasRequest && requestClass.isAssignableFrom(params.getClass())) {
            try {
                paramsObject = MetaObjectUtil.forObject(getParameterMap.invoke(params, new Object[]{}));
            } catch (Exception e) {
                //忽略
            }
        } else {
            paramsObject = MetaObjectUtil.forObject(params);
        }
        if (paramsObject == null) {
            throw new PageException("分页查询参数处理失败!");
        }
        Object orderBy = getParamValue(paramsObject, "orderBy", false);
        boolean hasOrderBy = false;
        if (orderBy != null && orderBy.toString().length() > 0) {
            hasOrderBy = true;
        }
        try {
            Object _pageNum = getParamValue(paramsObject, "pageNum", required);
            Object _pageSize = getParamValue(paramsObject, "pageSize", required);
            if (_pageNum == null || _pageSize == null) {
                if(hasOrderBy){
                    Page page = new Page();
                    page.setOrderBy(orderBy.toString());
                    page.setOrderByOnly(true);
                    return page;
                }
                return null;
            }
            pageNum = Integer.parseInt(String.valueOf(_pageNum));
            pageSize = Integer.parseInt(String.valueOf(_pageSize));
        } catch (NumberFormatException e) {
            throw new PageException("分页参数不是合法的数字类型!");
        }
        Page page = new Page(pageNum, pageSize);
        //count查询
        Object _count = getParamValue(paramsObject, "count", false);
        if (_count != null) {
            page.setCount(Boolean.valueOf(String.valueOf(_count)));
        }
        //排序
        if (hasOrderBy) {
            page.setOrderBy(orderBy.toString());
        }
        //分页合理化
        Object reasonable = getParamValue(paramsObject, "reasonable", false);
        if (reasonable != null) {
            page.setReasonable(Boolean.valueOf(String.valueOf(reasonable)));
        }
        //查询全部
        Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false);
        if (pageSizeZero != null) {
            page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero)));
        }
        return page;
    }

从以上简单代码中我们可以发现,如果sql入参中存在 orderby或者同时存在pageNumpageSize那么page还是不等于null,即skip!=true

跳过查总数据

回到PageInterceptor的intercept方法,skip = true走分页流程时会判断是否需要进行 count 查询

if (dialect.beforeCount(ms, parameter, rowBounds))
...
public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
        Page page = getLocalPage();
        return !page.isOrderByOnly() && page.isCount();
    }

当page不是只orderBy时并且page.isCount()为true时,需要进行count查询,那么简单破坏Page就能达到跳过count查总数据需求。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游语

对你有帮助,可以请我喝杯奶哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值