zoukankan      html  css  js  c++  java
  • PageHelper实现分页原理

    com.github.pagehelper.PageHelper是一个开源的分页源码工具; 第一次看的时候不知道分页原理是什么?

    看代码:

        @Override
        public ResultUtil selLogList(Integer page, Integer limit,UserSearch search) {
            PageHelper.startPage(page, limit);
            TbLogExample example=new TbLogExample();
            //设置按创建时间降序排序
            example.setOrderByClause("id DESC");
            Criteria criteria = example.createCriteria();
            
            if(search.getOperation()!=null&&!"".equals(search.getOperation())){
                criteria.andOperationLike("%"+search.getOperation()+"%");
            }
            
            if(search.getCreateTimeStart()!=null&&!"".equals(search.getCreateTimeStart())){
                criteria.andCreateTimeGreaterThanOrEqualTo(MyUtil.getDateByString(search.getCreateTimeStart()));
            }
            if(search.getCreateTimeEnd()!=null&&!"".equals(search.getCreateTimeEnd())){
                criteria.andCreateTimeLessThanOrEqualTo(MyUtil.getDateByString(search.getCreateTimeEnd()));
            }
            
            List<TbLog> logs = tbLogMapper.selectByExample(example);
            PageInfo<TbLog> pageInfo = new PageInfo<TbLog>(logs);
            ResultUtil resultUtil = new ResultUtil();
            resultUtil.setCode(0);
            resultUtil.setCount(pageInfo.getTotal());
            resultUtil.setData(pageInfo.getList());
            return resultUtil;
        }

    在dao层调用selectByExample之前只使用了

    PageHelper.startPage(page, limit);进行分页。

    在这两者之间似乎并没有什么重要的关联,没有相互引用。

    再看mybatis的xml文件。

      <select id="selectByExample" resultMap="BaseResultMap" parameterType="com.hfcx.pojo.TbLogExample" >
        select
        <if test="distinct" >
          distinct
        </if>
        <include refid="Base_Column_List" />
        from tb_log
        <if test="_parameter != null" >
          <include refid="Example_Where_Clause" />
        </if>
        <if test="orderByClause != null" >
          order by ${orderByClause}
        </if>
      </select>

    一般来说limit是写在order by之后的,可是xml文件中并没有limit。

    这时我们看一下PageHelper.startPage(page, limit);的源码;

        /**
         * 开始分页
         *
         * @param pageNum      页码
         * @param pageSize     每页显示数量
         * @param count        是否进行count查询
         * @param reasonable   分页合理化,null时用默认配置
         * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置
         */
        public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
            Page<E> page = new Page<E>(pageNum, pageSize, count);
            page.setReasonable(reasonable);
            page.setPageSizeZero(pageSizeZero);
            //当已经执行过orderBy的时候
            Page<E> oldPage = SqlUtil.getLocalPage();
            if (oldPage != null && oldPage.isOrderByOnly()) {
                page.setOrderBy(oldPage.getOrderBy());
            }
            SqlUtil.setLocalPage(page);
            return page;
        }

    在这段代码中方法内第一行是写入参数,第二个和第三个都是为null,不去考虑。

    重点在于SqlUtil.getLocalPage();和SqlUtil.setLocalPage(page);方法。

    这里是使用进行分页的,继续进去看源代码;

        /**
         * 获取Page参数
         *
         * @return
         */
        public static <T> Page<T> getLocalPage() {
            return LOCAL_PAGE.get();
        }
    
        public static void setLocalPage(Page page) {
            LOCAL_PAGE.set(page);
        }

    这里有一个LOCAL_PAGE;

    这里用到了一个ThreadLocal;

    ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。

    ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

     然后就看不到任何关联了,注意上面是有一个注释,叫 Mybatis - 通用分页拦截器

    那么在哪里拦截了呢?

    很熟悉,我们必须要配置的一个配置文件:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    <!-- 配置分页插件 -->
        <plugins>
            <plugin interceptor="com.github.pagehelper.PageHelper">
                <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->        
                <property name="dialect" value="mysql"/>
            </plugin>
        </plugins>
    </configuration>

    且这里是实现了拦截器的方法:

     *    Copyright 2009-2012 the original author or authors.
    package org.apache.ibatis.plugin;
    
    import java.util.Properties;
    
    /**
     * @author Clinton Begin
     */
    public interface Interceptor {
    
      Object intercept(Invocation invocation) throws Throwable;
    
      Object plugin(Object target);
    
      void setProperties(Properties properties);
    
    }

    经过debug,发现拦截器实现是在执行搜索方法selectByExample时候拦截的。

    至于怎么通过注解拦截之类的不多说,直接debug分析。

    下一步:

    这里的autoRuntimeDialect和autoDialect都为false。在processPage方法下打断点

    当然不是在result打断点,为了方便,是在_processPage方法下打断点。

    这里

    是有通过反射获取参数的,包括方法和类;

    这时候page已经获得一些参数了,但是并没有获取到查询的数据

     

    一直往下,直到这里;

    注释的很详细。这里获取的是总数。不涉及分页,跳过;继续下一步

    这里很重要

     这里使用的就是设计模式中的桥接模式;实现parser接口的有mysql,oracle,PostgreSQL等等。

    这里实现了拼接;

    再反射执行结果,获取到了值。

    至于getPageSql方法在什么时候调用拼接的,暂时没找到,找到补充

  • 相关阅读:
    48音标
    business expressions(二)
    Pick up lines搭讪
    Greetings
    business expressions(一)
    analyzing problems
    business meeting
    idea缓存目录mac cache
    Sublime 3156 LICENSE key
    React从0到1
  • 原文地址:https://www.cnblogs.com/zhengyuanyuan/p/10767408.html
Copyright © 2011-2022 走看看