PageHelper插件的认识

一  前言

对于pageHelper 插件的使用呢,一直稀里糊涂,结果是分页能不能成功全靠运气。于是自己大致跟了下代码,虽然好多也没看懂,仅当自己的学习笔记啦。如果能帮到网友,就同乐了呀!

二 使用

 @Override
    public PageInfo<ReportInfo> physicalreportlist(ReportReqVo reportReqVo, Integer         pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<ReportInfo> req = reportMapper.findByCondition(reportReqVo);
        PageInfo<ReportInfo> page = new PageInfo<>(req);

        List<ReportInfo> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(req)) {
            result= reportMapper.selectphysicalreportlist(req);
        }
        page.setList(result);
        return page;
    }

      说明:对于单条sql查询,只要把查询语句紧挨着写在PageHelper.startPage(pageNum, pageSize)下面。如果一条sql查询不能搞定,也是将第一次查询的sql紧挨着写在pageHelper.startPage(pageNum, pageSize)下面。多次查询,肯定有个初始数据源。像我这里,req就是初始数据,查出所有id,供第二次查询用。

      注意:PageHelper.startpage()执行后就开始分页,第一行sql每次都执行pageSize。按道理讲,第二次查询和第一次查询的

条数应该是一样的,不然,你分页信息是每页10条,但是实际情况少于10条。所以这里要注意两点:

              1 第二次最好根据id查询

              2 left join也可能影响第二次查询结果的条数。

      这里可以做个试验。将这里第二查询语句,假如只取前5条,你会在页面看到这样的信息:分页信息都是对的,只是每页分页的数据只有5条!

      建议:最好按照下面的步骤写!

              1 

 PageHelper.startPage(pageNum, pageSize);
 List<ReportInfo> req = reportMapper.findByCondition(reportReqVo);
 PageInfo<ReportInfo> page = new PageInfo<>(req);

              2 做二次处理(可能不需要)

              3 return page

三 原理简单分析

       第一行:PageHelpler.startPage(pageNum, pageSize) 就会把分页初始信息准备好,还有个默认参数count(默认值true),查询出total(总条数)。

        截取部分代码:注意这里的setLocalPage()

        Page<E> page = new Page<E>(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        //当已经执行过orderBy的时候
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;

 

       第二行:执行了第一行代码后,他已经控制了第二条查询语句每次查询的条数。原来,在执行sql前,插件使用使用了拦截器,保证这条sql每次只执行pageSize条。具体实现不是很清楚。而且每次都会查询出count

 

       截取部分代码:

       

public Object intercept(Invocation invocation) throws Throwable {
        try {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds) args[2];
            ResultHandler resultHandler = (ResultHandler) args[3];
            Executor executor = (Executor) invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            //由于逻辑关系,只会进入一次
            if(args.length == 4){
                //4 个参数时
                boundSql = ms.getBoundSql(parameter);
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                //6 个参数时
                cacheKey = (CacheKey) args[4];
                boundSql = (BoundSql) args[5];
            }
            List resultList;
            //调用方法判断是否需要进行分页,如果不需要,直接返回结果
            if (!dialect.skip(ms, parameter, rowBounds)) {
                //反射获取动态参数
                String msId = ms.getId();
                Configuration configuration = ms.getConfiguration();
                Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
                //判断是否需要进行 count 查询
                if (dialect.beforeCount(ms, parameter, rowBounds)) {
                    String countMsId = msId + countSuffix;
                    Long count;
                    //先判断是否存在手写的 count 查询
                    MappedStatement countMs = getExistedMappedStatement(configuration, countMsId);
                    if(countMs != null){
                        count = executeManualCount(executor, countMs, parameter, boundSql, resultHandler);
                    } else {
                        countMs = msCountMap.get(countMsId);
                        //自动创建
                        if (countMs == null) {
                            //根据当前的 ms 创建一个返回值为 Long 类型的 ms
                            countMs = MSUtils.newCountMappedStatement(ms, countMsId);
                            msCountMap.put(countMsId, countMs);
                        }
                        count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);
                    }
                    //处理查询总数
                    //返回 true 时继续分页查询,false 时直接返回
                    if (!dialect.afterCount(count, parameter, rowBounds)) {
                        //当查询总数为 0 时,直接返回空的结果
                        return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                    }
                }

 

 

 

       第三行:截取了部分代码:

         if (list instanceof Page) {
            Page page = (Page) list;
            this.pageNum = page.getPageNum();
            this.pageSize = page.getPageSize();

            this.pages = page.getPages();
            this.list = page;
            this.size = page.size();
            this.total = page.getTotal();
            //由于结果是>startRow的,所以实际的需要+1
            if (this.size == 0) {
                this.startRow = 0;
                this.endRow = 0;
            } else {
                this.startRow = page.getStartRow() + 1;
                //计算实际的endRow(最后一页的时候特殊)
                this.endRow = this.startRow - 1 + this.size;
            }
           ....
           ....

         }

       这一句主要目的,我认为就是获取整个分页信息!

       这里只是冰山一角,有好多没看懂,list强制转成page对象后,debug中根据获取不到pages total信息,是我太菜了呀!

      

四 补充

       先这样吧,以后再补充,不过一定要按照我上面的步骤写分页。有不对的,请指明!

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值