• PageHelper原理


    PageHelper是什么

    基于mybatis的一款分页插件,仅用少量代码即可实现分页功能

    查询数量sql怎么生成的

    修改了原生的sqlSource,产生了count的MappedStatement

        public static MappedStatement newCountMappedStatement(MappedStatement ms) {
            MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId() + "_COUNT", ms.getSqlSource(), ms.getSqlCommandType());
            builder.resource(ms.getResource());
            builder.fetchSize(ms.getFetchSize());
            builder.statementType(ms.getStatementType());
            builder.keyGenerator(ms.getKeyGenerator());
            if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
                StringBuilder keyProperties = new StringBuilder();
                for (String keyProperty : ms.getKeyProperties()) {
                    keyProperties.append(keyProperty).append(",");
                }
                keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
                builder.keyProperty(keyProperties.toString());
            }
            builder.timeout(ms.getTimeout());
            builder.parameterMap(ms.getParameterMap());
            //count查询返回值int
            List<ResultMap> resultMaps = new ArrayList<ResultMap>();
            ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), int.class, EMPTY_RESULTMAPPING).build();
            resultMaps.add(resultMap);
            builder.resultMaps(resultMaps);
            builder.resultSetType(ms.getResultSetType());
            builder.cache(ms.getCache());
            builder.flushCacheRequired(ms.isFlushCacheRequired());
            builder.useCache(ms.isUseCache());
    
            return builder.build();
        }
    

    分页sql怎么产生的

    对于不同的数据源做不同的处理,对mysql而言,就是产生了对应的limit语句

    public class MysqlParser extends AbstractParser {
        @Override
        public String getPageSql(String sql) {
            StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
            sqlBuilder.append(sql);
            sqlBuilder.append(" limit ?,?");
            return sqlBuilder.toString();
        }
    
        @Override
        public Map<String, Object> setPageParameter(MappedStatement ms, Object parameterObject, BoundSql boundSql, Page<?> page) {
            Map<String, Object> paramMap = super.setPageParameter(ms, parameterObject, boundSql, page);
            paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());
            paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());
            return paramMap;
        }
    }
    

    分页参数怎么保存的

    通过startPage方法,将分页参数放到ThreadLocal中

        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;
        }
    

    插件如何融于mybatis中

    通过注册mybatis插件,PageHelper实现了Interceptor接口,核心的处理逻辑都在intercept方法中

        /**
         * Mybatis拦截器方法
         *
         * @param invocation 拦截器入参
         * @return 返回执行结果
         * @throws Throwable 抛出异常
         */
        public Object intercept(Invocation invocation) throws Throwable {
            if (autoRuntimeDialect) {
                SqlUtil sqlUtil = getSqlUtil(invocation);
                return sqlUtil.processPage(invocation);
            } else {
                if (autoDialect) {
                    initSqlUtil(invocation);
                }
                return sqlUtil.processPage(invocation);
            }
        }
    

    sqlSource的动态判断

        public void processMappedStatement(MappedStatement ms) throws Throwable {
            SqlSource sqlSource = ms.getSqlSource();
            MetaObject msObject = SystemMetaObject.forObject(ms);
            SqlSource pageSqlSource;
            if (sqlSource instanceof StaticSqlSource) {
                pageSqlSource = new PageStaticSqlSource((StaticSqlSource) sqlSource);
            } else if (sqlSource instanceof RawSqlSource) {
                pageSqlSource = new PageRawSqlSource((RawSqlSource) sqlSource);
            } else if (sqlSource instanceof ProviderSqlSource) {
                pageSqlSource = new PageProviderSqlSource((ProviderSqlSource) sqlSource);
            } else if (sqlSource instanceof DynamicSqlSource) {
                pageSqlSource = new PageDynamicSqlSource((DynamicSqlSource) sqlSource);
            } else {
                throw new RuntimeException("无法处理该类型[" + sqlSource.getClass() + "]的SqlSource");
            }
            msObject.setValue("sqlSource", pageSqlSource);
            //由于count查询需要修改返回值,因此这里要创建一个Count查询的MS
            msCountMap.put(ms.getId(), MSUtils.newCountMappedStatement(ms));
        }
    

    parser的动态判断

    从sql链接中获取方言,例如mysql,通过mysql判断

        public static Parser newParser(Dialect dialect) {
            Parser parser = null;
            switch (dialect) {
                case mysql:
                case mariadb:
                case sqlite:
                    parser = new MysqlParser();
                    break;
                case oracle:
                    parser = new OracleParser();
                    break;
                case hsqldb:
                    parser = new HsqldbParser();
                    break;
                case sqlserver:
                    parser = new SqlServerParser();
                    break;
                case sqlserver2012:
                    parser = new SqlServer2012Dialect();
                    break;
                case db2:
                    parser = new Db2Parser();
                    break;
                case postgresql:
                    parser = new PostgreSQLParser();
                    break;
                case informix:
                    parser = new InformixParser();
                    break;
                case h2:
                    parser = new H2Parser();
                    break;
                default:
                    throw new RuntimeException("分页插件" + dialect + "方言错误!");
            }
            return parser;
        }
    

    参考

  • 相关阅读:
    关于SDK-manager中我们需要下载哪些?
    不只是撸代码搞鸡汤,也有故事!
    [Selenium]如何通过Selenium实现Ctrl+click,即按住Ctrl的同时进行单击操作
    【设计模式】单例模式
    【Java多线程】线程池学习
    【leetcode】147 Insertion Sort List
    【webssh】shellinabox搭建
    【SpringMVC】一次处理项目中文乱码的经历
    【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore
    【leetcode】3 SUM
  • 原文地址:https://www.cnblogs.com/seekwind/p/14325304.html
Copyright © 2020-2023  润新知