美文网首页mybatis
mybatis源码分析-selectOne-02

mybatis源码分析-selectOne-02

作者: 愤怒的奶牛 | 来源:发表于2019-10-07 19:26 被阅读0次

    上篇说到 DefaultSqlSession 中的 selectList() 方法,知道 执行具体的查询是 交给了 executor 接口。接下来我们接着看

      @Override
      public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
          MappedStatement ms = configuration.getMappedStatement(statement);
          return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
    executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    
    1.1 Executor 接口
    /**
     * @author Clinton Begin
     */
    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.png

    接下来我们需要知道 executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 这句代码走的是哪一个实现类,我们可以debug 一下,然后我们再从源码里面找具体的代码。debug 得出的 是 CachingExecutor ,我们接下来分析为什么是 这个实现类,当前executor.query() 是在DefaultsSqlSession 接口中,所以我们现需要从 DefaultsSqlSession 中找到答案。为了方便阅读我们贴一下 DefaultSqlSessionFactory 中的源码:工厂模式体现

    public class DefaultSqlSessionFactory implements SqlSessionFactory {
    
      private final Configuration configuration;
    
      public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
      }
    
      @Override
      public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
      }
    
      @Override
      public SqlSession openSession(boolean autoCommit) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType) {
        return openSessionFromDataSource(execType, null, false);
      }
    
      @Override
      public SqlSession openSession(TransactionIsolationLevel level) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return openSessionFromDataSource(execType, level, false);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
        return openSessionFromDataSource(execType, null, autoCommit);
      }
    
      @Override
      public SqlSession openSession(Connection connection) {
        return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, Connection connection) {
        return openSessionFromConnection(execType, connection);
      }
    
      @Override
      public Configuration getConfiguration() {
        return configuration;
      }
    // 上面的方法都会复用这里的方法。至于为什么是 DefaultSqlSession 接口 可以参考上一篇文章 selectOne-01
      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);
    //初始化了 Executor  对象
          final Executor executor = configuration.newExecutor(tx, execType);
    // 创建 DefaultSqlSession 对象,并传入 Executor   对象,所以答案就在这里,这里就说明了 DefaultSqlSession 中使用的 Executor   对象。
          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();
        }
      }
    ... 部分方法省略
    
    1.2 final Executor executor =configuration.newExecutor(tx, execType);
      final Executor executor = configuration.newExecutor(tx, execType); //创建了 Executor  对象,接下来我们就来分析 这个对象具体的 实现是哪个
    
    public class Configuration {
    
      protected Environment environment;
    
      .... 省略部分
      protected boolean cacheEnabled = true;
     .... 省略部分
     // SqlSession sqlSession = sqlSessionFactory.openSession();
      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 { // executorType 默认值  ExecutorType.SIMPLE,所以会执行 下面这句话
          executor = new SimpleExecutor(this, transaction);
        }
        if (cacheEnabled) {// true
          executor = new CachingExecutor(executor); // 委派模式
        }
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
      }
    
      if (cacheEnabled) {// true
          executor = new CachingExecutor(executor); // 静态代理
        }
    

    这里补贴一下 openSession() 方法的逻辑,这里有一点 跳跃 ,但是这里的 源码中的逻辑 比较简单 ,容易看懂,我们可以进源码仔细
    跟一下我们 能够容易的得出 onfiguration.getDefaultExecutorType() => ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

    DefaultSqlSessionFactory 中
     @Override
      public SqlSession openSession() {
    // configuration.getDefaultExecutorType() => ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
      }
    
    

    上面这就告诉我们,我们拿到的对象是 CachingExecutor 对象。该对象 通过静态代理的方式,目标对象是 SimpleExecutor 接口。
    从上面的源码分析中,我们就能回答前面的问题了 ,
    Executor 接口 的实现类就 是 CachingExecutor 。更具体一点,CachingExecutor 接口采用委派模式 ,委派模式中的特点之一就是 ,自己一定不会干活,干活的都是下面的,所以 我们可以说 Executor 接口 中执行 具体查询 任务的是 SimpleExecutor 接口。至于为什么要有 CachingExecutor 接口,我们到后面再来分析,为了不 淹没我们的主线任务,暂时不分析 具体原因,但有一点能肯定:就是优化查询。后面我们会 分析 CachingExecutor 接口 ,以及 SimpleExecutor 接口,涉及到的理论就是 静态代理。敬请关注 mybatis源码分析-selectOne-03

    相关文章

      网友评论

        本文标题:mybatis源码分析-selectOne-02

        本文链接:https://www.haomeiwen.com/subject/xlfmpctx.html