zoukankan      html  css  js  c++  java
  • SqlSession对象之Executor

    Executor是Mybatis的一个核心接口,每一个SqlSession对象都会拥有一个Executor(执行器对象);这个执行对象负责[增删改查]的具体操作,我们可以简单的将它理解为JDBC中Statement的封装版。它的代码如下:

    public interface Executor {
      ResultHandler NO_RESULT_HANDLER = null;
      int update(MappedStatement ms, Object parameter) throws SQLException;
      <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
      <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
      <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
      List<BatchResult> flushStatements() throws SQLException;
      void commit(boolean required) throws SQLException;
      void rollback(boolean required) throws SQLException;
      CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
      boolean isCached(MappedStatement ms, CacheKey key);
      void clearLocalCache();
      void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
      Transaction getTransaction();
      void close(boolean forceRollback);
      boolean isClosed();
      void setExecutorWrapper(Executor executor);
    }
    

    一、Executor的继承结构

    Executor的类图如下所示:

    Executor是一个接口,主要有两个实现类:分别是BaseExecutor和CachingExecutor。

    1、BaseExecutor类

    BaseExecutor是一个抽象类,这种通过抽象类实现接口的方式是适配器设计模式的体现,主要用于方便次一级子类对接口中方法的实现。BaseExecutor主要有三个实现类SimpleExecutorReuseExecutorBatchExecutor。三个实现类分别对应executor对Statement对象管理方案。

    • 简单方案:一个Statement接口对象只执行一次,执行完毕就会Statement接口对象进行销毁。对应SimpleExecutor,被称为简单执行器,是MyBatis中默认使用的执行器,每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象(可以是Statement或PrepareStatement对象)。
    • 可重用方案:对应ReuseExecutor,被称为可重用执行器,重用指的是重复使用Statement,它会在内部利用一个Map把初始化的Statement都缓存起来,每次在执行一条SQL语句时,它都会去判断之前是否存在基于该SQL缓存的Statement对象,存在而且之前缓存的Statement对象对应的Connection还没有关闭的时候就继续用之前的Statement对象,否则将初始化一个新的Statement对象,并将其缓存起来。因为每一个新的SqlSession都有一个新的Executor对象,所以我们缓存在ReuseExecutor上的Statement的作用域是同一个SqlSession。
    • 批量处理方案:对应BatchExecutor,称为批处理执行器,用于将多个Statement对应的SQL语句,交给一个Statement对象一次输送到数据库,进行批处理操作。

    2、CachingExecutor类

    CachingExecutor称为缓存执行器,MyBatis框架默认情况下使用执行器缓存执行器,可以提高查询效率,先从缓存中获取查询结果,存在就返回,不存在,再委托给Executor delegate去数据库取,delegate可以是SimpleExecutor、ReuseExecutor、BatchExecutor中任意一个。

    二、Executor对象初始化

    Executor的初始化是在SqlSessionFactory调用openSession方法期间初始化的,首先看一下SqlSessionFactory中的方法,具体代码如下:

    public interface SqlSessionFactory {
    
      SqlSession openSession();
    
      SqlSession openSession(boolean autoCommit);
      SqlSession openSession(Connection connection);
      SqlSession openSession(TransactionIsolationLevel level);
    
      SqlSession openSession(ExecutorType execType);
      SqlSession openSession(ExecutorType execType, boolean autoCommit);
      SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
      SqlSession openSession(ExecutorType execType, Connection connection);
    
      Configuration getConfiguration();
    
    }
    

    由代码可见,SqlSessionFactory中的openSession方法分为两类:带ExecutorType和不带ExecutorType的,此外每个类型还有四种,这里采用了重载的方法,方法名称相同,参数列表不同。下面进入到SqlSessionFactory的实现类DefaultSqlSessionFactory中查看openSession()d的实现,代码如下:

      @Override
      public SqlSession openSession(ExecutorType execType) {
        return openSessionFromDataSource(execType, null, false);
      }
    
      @Override
      public SqlSession openSession(TransactionIsolationLevel level) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
      }
    ...
    

    通过查看代码发现,所有的openSession方法都会走向openSessionFromDataSource方法中,openSessionFromDataSource的代码如下:

    private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
        try {
          boolean autoCommit;
          try {
            autoCommit = connection.getAutoCommit();
          } catch (SQLException e) {
            autoCommit = true;
          }      
          final Environment environment = configuration.getEnvironment();
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          final Transaction tx = transactionFactory.newTransaction(connection);
          final Executor executor = configuration.newExecutor(tx, execType);
          return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    

    主要看其中的两行代码:

     final Executor executor = configuration.newExecutor(tx, execType);
     return new DefaultSqlSession(configuration, executor, autoCommit);
    

    这两行代码先产生executor,再产生了DefaultSqlSession对象,也验证了前面所说的执行器的初始化是在SqlSession初始化之前进行的。下面我们继续查看执行器的初始化过程,它的初始化是由Configuration完成的,初始化Executor的方法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) interceptorChain.pluginAll(executor);
        return executor;
    }
    
    protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
    

    由代码可见:首先判断初始化ExecutorType是否为空,若不为空,则默认执行器为SimpleExecutor。而这里的ExecutorType类型则是由openSession方法传入的,因而SqlSessionFactory中没有ExecutorType参数的openSession()则默认为SimpleExecutor。此外关注以下代码:

    protected boolean cacheEnabled = true;
    
    if (cacheEnabled) {
          executor = new CachingExecutor(executor);
    }
    

    这里是初始化CachingExecutor执行器,可见默认情况下CachingExecutor执行器是开启的。

    三、ExecutorType的选择

    ExecutorType是枚举类型,其代码如下:

    public enum ExecutorType {
      SIMPLE, REUSE, BATCH
    }
    

    ExecutorType的枚举值分别对应三种执行器类型:简单执行器、可重用执行器、批量执行器。

    ExecutorType的类型选择,有两种方式对其进行赋值。

    1、<settings>标签设置

    通过<settings>标签来设置当前工程中所有SqlSession对象使用的默认Executour。

    2、openSession方法指定

    通过SqlSessoinFactory中openSession方法来指定具体的SqlSession使用的执行器。

  • 相关阅读:
    面试干货——年底干货大放送,你准备好了吗?(转)
    JavaScript学习 三、变量、作用域和内存
    JavaScript学习 二、基础
    JavaScript学习 一、简介
    从统计看机器学习常见算法
    [zz]unity 性能优化
    游戏统计指标
    [zz]sql优化相关
    [zz]sql语句执行顺序
    unity 链接
  • 原文地址:https://www.cnblogs.com/liuyi6/p/10085378.html
Copyright © 2011-2022 走看看