mybatis-plus分页插件失效探究解决

 更新时间:2023年07月06日 09:35:00   作者:子瞻  
这篇文章主要为大家介绍了mybatis-plus分页插件失效探究解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

网上推荐

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

@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。

以上就是mybatis-plus分页插件失效探究解决的详细内容,更多关于mybatis plus分页插件失效的资料请关注脚本之家其它相关文章!

相关文章

  • Java 将Excel转为OFD格式(方法步骤)

    Java 将Excel转为OFD格式(方法步骤)

    OFD是一种开放版式文档是我国国家版式文档格式标准,本文通过Java后端程序代码展示如何将Excel转为OFD格式,分步骤给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2021-12-12
  • java结合WebSphere MQ实现接收队列文件功能

    java结合WebSphere MQ实现接收队列文件功能

    WebSphereMQ,也称MQSeries,以一致的、可靠的和易于管理的方式来连接应用程序,并为跨部门、企业范围的集成提供了可靠的基础。通过为重要的消息和事务提供可靠的、一次且仅一次的传递,MQ可以处理复杂的通信协议,并动态地将消息传递工作负载分配给可用的资源。
    2015-10-10
  • Spring中的@Conditional注解实现分析

    Spring中的@Conditional注解实现分析

    这篇文章主要介绍了Spring中的@Conditional注解实现分析,  @Conditional是Spring 4出现的注解,但是真正露出价值的是Spring Boot的扩展@ConditionalOnBean等,需要的朋友可以参考下
    2023-12-12
  • Java中调用SQL Server存储过程详解

    Java中调用SQL Server存储过程详解

    这篇文章主要介绍了Java中调用SQL Server存储过程详解,本文讲解了使用不带参数的存储过程、使用带有输入参数的存储过程、使用带有输出参数的存储过程、使用带有返回状态的存储过程、使用带有更新计数的存储过程等操作实例,需要的朋友可以参考下
    2015-01-01
  • SpringBoot实现热部署详解

    SpringBoot实现热部署详解

    SpringBoot热部署是一种开发时极为有用的功能,它能够让开发人员在代码修改后无需手动重启应用程序就能立即看到变化的效果,所以我本文就给打击介绍一下为什么要使用热部署以及实现热部署的方式,需要的朋友可以参考下
    2023-07-07
  • Java高效实现excel转pdf(支持带图片的转换)

    Java高效实现excel转pdf(支持带图片的转换)

    这篇文章主要为大家详细介绍了如何用java实现excel转pdf文件,并且支持excel单元格中带有图片的转换,文中的示例代码讲解详细,需要的可以参考下
    2024-01-01
  • Java生成二维码的2种实现方法

    Java生成二维码的2种实现方法

    这篇文章主要给大家介绍了关于Java生成二维码的2种实现方法,二维码的实质就是一个链接地址,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Java如何读取jar包中的resource资源文件

    Java如何读取jar包中的resource资源文件

    这篇文章主要介绍了Java如何读取jar包中的resource资源文件,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • JAVA构造函数不能使用void关键字问题

    JAVA构造函数不能使用void关键字问题

    这篇文章主要介绍了JAVA构造函数不能使用void关键字问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • Java操作Redis详细介绍

    Java操作Redis详细介绍

    这篇文章主要介绍了Java操作Redis详细介绍,涉及对key的操作,string数据类型,list数据类型等相关内容,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11

最新评论