若依框架---PageHelper分页(四)

简介: 若依框架---PageHelper分页(四)

我们通过下载并查看PageHelper-Spring-Boot-Starter源码,了解到PageHelper是通过实现MyBatis拦截器接口org.apache.ibatis.plugin.InterceptorPageInterceptor类从而实现对SQL重写的。


那么问题来了XDM, PageInterceptor又是具体如何重写SQL的呢?


我们知道拦截器一般是通过反射机制实现的。(本文暂不展开说)。


拦截器中最重要的方法一般命名为intercept,形式一般是下面代码的样子:

@Override
    public Object intercept(Invocation invocation) {
        // 逻辑代码前
        invocation.invoke(); // 执行所拦截的实际代码
        // 逻辑代码后
    }


这里的invocation.invoke()实际就是相当于我们去执行接口代码或者是执行SQL,如此我们便可以全局的对程序接口或者SQL做某些修改。


我们来看一下PageInterceptor的拦截器代码:

@Override
    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];
            }
            checkDialectExists();
            //对 boundSql 的拦截处理
            if (dialect instanceof BoundSqlInterceptor.Chain) {
                boundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.ORIGINAL, boundSql, cacheKey);
            }
            List resultList;
            //调用方法判断是否需要进行分页,如果不需要,直接返回结果
            if (!dialect.skip(ms, parameter, rowBounds)) {
                //判断是否需要进行 count 查询
                if (dialect.beforeCount(ms, parameter, rowBounds)) {
                    //查询总数
                    Long count = count(executor, ms, parameter, rowBounds, null, boundSql);
                    //处理查询总数,返回 true 时继续分页查询,false 时直接返回
                    if (!dialect.afterCount(count, parameter, rowBounds)) {
                        //当查询总数为 0 时,直接返回空的结果
                        return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                    }
                }
                resultList = ExecutorUtil.pageQuery(dialect, executor,
                        ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
            } else {
                //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
                resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
            }
            return dialect.afterPage(resultList, parameter, rowBounds);
        } finally {
            if(dialect != null){
                dialect.afterAll();
            }
        }
    }


代码有点多,我们来逐行分析:


前4句,获取拦截中的参数:

Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
RowBounds rowBounds = (RowBounds) args[2];
ResultHandler resultHandler = (ResultHandler) args[3];


类型依次为 MappedStatementObjectRowBoundsResultHandler,为了更清楚,我们简单列出其结构:大致可以根据其参数了解这个参数大概是什么类型


    • MappedStatement (resource, configuration, id, fetchSize, timeout, statementType, resultSetType, sqlSource, cache, parameterMap, resultMaps, ..., sqlCommandType, keyGenerator,keyProperties, keyColumns, databaseId, statementLog, LanguageDriver, resultSets);
    • Object, 不做叙述;
    • RowBounds: offset, limit, (类中还有常量NO_ROW_OFFSET=0, NO_ROW_LIMIT = 2147483647);
    • ResultHandler<T>:只有一个抽象方法:
    public abstract  void handleResult(org.apache.ibatis.session.ResultContext<? extends T> arg0);
    


    又是从哪里拦截到的这几个参数呢?或者说,我们拦截的到底是个什么东东?


    PageHelper的wiki文档给出了答案:org.apache.ibatis.executor.Executor.


    wiki中说:


    在 MyBatis 的拦截器的文档部分,我们知道 Executor 中的 query 方法可以被拦截


    其query方法形式为:

    <E> List<E> query(
          MappedStatement ms, 
          Object parameter, 
          RowBounds rowBounds, 
          ResultHandler resultHandler) throws SQLException;


    看,是不是对应上了4个参数!


    话说谁发明的springboot这种接口与实现模式,源码看的类似了,一顿翻找还是漏掉不少源码。

    目录
    相关文章
    |
    SQL Oracle 关系型数据库
    若依框架---PageHelper分页(七)
    若依框架---PageHelper分页(七)
    393 0
    |
    SQL Java 关系型数据库
    若依框架---PageHelper分页(十一)
    若依框架---PageHelper分页(十一)
    579 0
    |
    SQL 数据库
    若依框架---PageHelper分页(六)
    若依框架---PageHelper分页(六)
    410 0
    |
    JavaScript Java
    若依框架 - - - 自定义打印模版
    若依框架 - - - 自定义打印模版
    1308 0
    若依框架 - - - 自定义打印模版
    |
    前端开发 数据安全/隐私保护
    若依框架---权限控制角色设计
    若依框架---权限控制角色设计
    4253 0
    |
    Prometheus 监控 安全
    SpringBoot Actuator未授权访问漏洞的解决方法
    SpringBoot Actuator未授权访问漏洞的解决方法Actuator 是 SpringBoot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计等。
    32233 0
    |
    SQL Oracle 关系型数据库
    若依框架---PageHelper分页(五)
    若依框架---PageHelper分页(五)
    540 0
    |
    SQL Java 数据库连接
    若依框架---PageHelper分页(三)
    若依框架---PageHelper分页(三)
    557 0
    |
    监控 Java Nacos
    使用Spring Boot集成Nacos
    通过上述步骤,Spring Boot应用可以成功集成Nacos,利用Nacos的服务发现和配置管理功能来提升微服务架构的灵活性和可维护性。通过这种集成,开发者可以更高效地管理和部署微服务。
    4513 17
    |
    Java Spring
    springboot项目读取 resources 目录下的文件的9种方式(总结)
    springboot项目读取 resources 目录下的文件的9种方式(总结)
    8225 1

    热门文章

    最新文章