网上基本上都是举荐配置如下:

    @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor() {        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));        return mybatisPlusInterceptor;    }

然而,仅仅这么做,就能达到咱们的预期吗?其终局就是分页插件没有成果,起因是为什么呢?

图1

图2

通过比照下面两张图能够发现,图一DefaultSqlSession.selectList()底层调用Plugin.invoke();图二DefaultSqlSession.selectList()底层调用CachingExecutor.query()。其中,图一是分页插件失效的调用链,图二是分页插件生效的调用链。

也就是说,分页插件生效的起因是,mybatis-plusPlugin类没有为分页插件拦截器生成Executor代理。具体应该怎么做呢?像上面这样,在构建SqlSessionFactory时,须要在MybatisSqlSessionFactoryBean显示设置Plugin。

@Bean(name = "defaultSqlSessionFactory")    public SqlSessionFactory defaultSqlSessionFactory(){        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();        bean.setDataSource(dataSource);        //设置拦截器        bean.setPlugins(mybatisPlusInterceptor);        SqlSessionFactory sqlSessionFactory = bean.getObject();        //设置主动提交        sqlSessionFactory.openSession(true);        return sqlSessionFactory;}

那么,为分页插件生成代理类是在什么机会生成呢?先颁布答案:

//设置主动提交sqlSessionFactory.openSession(true);

调用链如下:


图3

咱再看细节:
DefaultSqlSessionFactory.openSessionFromDataSource()详情:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    Transaction tx = null;    try {      final Environment environment = configuration.getEnvironment();      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);      //这步很要害,创立执行者实例      final Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {      closeTransaction(tx); // may have fetched a connection so lets call close()      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {      ErrorContext.instance().reset();    }  }

Configuration.newExecutor()详情:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {    executorType = executorType == null ? defaultExecutorType : executorType;    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;    Executor executor;    if (ExecutorType.BATCH == executorType) {      executor = new BatchExecutor(this, transaction);    } else if (ExecutorType.REUSE == executorType) {      executor = new ReuseExecutor(this, transaction);    } else {      executor = new SimpleExecutor(this, transaction);    }    if (cacheEnabled) {      executor = new CachingExecutor(executor);    }    //对下面的executor进行代理(目标是把插件和执行器封装为代理类)    executor = (Executor) interceptorChain.pluginAll(executor);    return executor;  }

MybatisPlusInterceptor.pluginAll();

public Object pluginAll(Object target) {    for (Interceptor interceptor : interceptors) {      target = interceptor.plugin(target);    }    return target;  }

通过下面的重点code展现,咱们大抵理解了局部重要节点中分页插件代理类生成的逻辑。接下来咱们持续理解具体分页插件工作的成果。


图4

 public boolean willDoQuery(){        if (countMs != null) {            countSql = countMs.getBoundSql(parameter);        } else {            countMs = buildAutoCountMappedStatement(ms);            //生成查问count SQL            String countSqlStr = autoCountSql(page, boundSql.getSql());            PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);            //构建BoundSql            countSql = new BoundSql(countMs.getConfiguration(), countSqlStr, mpBoundSql.parameterMappings(), parameter);            PluginUtils.setAdditionalParameter(countSql, mpBoundSql.additionalParameters());        }        //查问 count 数值        List<Object> result = executor.query(countMs, parameter, rowBounds, resultHandler, cacheKey, countSql);}

接下来,PaginationInnerInterceptor.beforeQuery()生成分页sql;最终MybatisPlusInterceptor.intercept()外面的executor.query()执行分页sql。