• MyBatis 四大组件 Executor 执行器


    一、Executor功能概述

       每一个sql语句的执行都会先到Executor执行器中在调用相应StatementHandler执行jdbc操作。源码如下SimpleExecutor中的代码片段

      

    复制代码

      public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
          Configuration configuration = ms.getConfiguration();
        //调用StatmentHandler,通过控制器调用jdbc相关操作
          StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
          stmt = prepareStatement(handler, ms.getStatementLog());
          return handler.query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }

    复制代码

    二、Executor继承体系如下

        

    Executor 执行器接口,它有两个实现类,分别是BaseExecutor和 CachingExecutor

    BaseExecutor :是一个抽象类,这种通过抽象的实现接口的方式是适配器设计模式之接口适配的体现,是 Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor 的子类有三个,分别是SimpleExecutorReuseExecutorBatchExecutor

    SimpleExecutor: 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个 Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象)

    ReuseExecutor: 可重用执行器,这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的 Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。每个SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor 上的Statement 作用域是同一个 SqlSession。

    BatchExecutor: 批处理执行器,用于将多个SQL一次性输出到数据库

    CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在,就返回;如果不存在,再委托给 Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器,默认是simpleexecutor

    三、Executor创建过程源码分析

     (1)创建SqlSession时,可以指定Executor类型,mybatis中ExecutorType枚举类来指定,ExecutorType源码如下,分别指定BaseExecutor下面三个实现类

      

    public enum ExecutorType {
      SIMPLE, REUSE, BATCH
    }

         (2)根据传递ExecutorType类型可以指定Executor种类,默认不传参就是SimpleExecutor 

            SqlSession sqlsession=sqlsessionFactory.openSession();
         

         //SqlSession sqlsession=sqlsessionFactory.openSession(ExecutorType.REUSE);

      (3)、DefaultSqlSessionFactory中创建执行器,源码如下

    复制代码

      public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
      }

        
    private  SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
               //定义事物
                Transaction tx = null;
                try {
                 //mybatis配置文件中所有信息都封装到Configuration中,获取环境    ,Environment中有id、datasource、transactionFactory三个属性
                  final Environment environment = configuration.getEnvironment();
                  //获取事物工厂
                  final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
                  //根据工厂创建事物对象,直接    return new JdbcTransaction(ds, level, autoCommit);
                  tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
                  //创建执行器
                  final Executor executor = configuration.newExecutor(tx, execType);
                  //默认executor是CachingExecutor
                  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();
                }
              }

    复制代码

    (4)下面看执行器具体创建流程configuration.newExecutor(tx, execType)

     

    复制代码

      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);
        }
       //cacheEnabled默认ture开启二级缓存
        if (cacheEnabled) {
        //把简单执行器传递给CachingExecutor中的delegate属性,
          executor = new CachingExecutor(executor);
        }
       //mybatis责任链模式
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
      }
    
     
    

    public CachingExecutor(Executor delegate) {
      this.delegate = delegate;
      delegate.setExecutorWrapper(this);
    }

    
     

    复制代码

    (5)执行流程入下

       

  • 相关阅读:
    记一次授权的APK渗透测试
    Web.config在渗透中的作用
    ctf中关于syscall系统调用的简单分析
    【文件包含&条件竞争】详解如何利用session.upload_progress文件包含进行RCE
    利用python免杀cs shellcode
    记一次ARM架构的ROP利用
    改造冰蝎对抗waf&OpenRASP计划-初探
    java后台管理 开源_12款开源的JAVA后台管理项目
    ECS 选款利器!PTS助您快速上云!
    Ocelot 负载均衡
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13309216.html
Copyright © 2020-2023  润新知