mybatis源码解析(4)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/supermancaiwandong/article/details/43954679

Executor的query和doQuery

sorry,好久没更新了,今天有时间,就多写点吧!
上次讲到,在DefaultSqlSession中的selectList方法,调用了executor的query方法。但这个query的方法具体是怎么实现的呢?这节来分析这个。
首先我看来看看这个executor究竟是那个实现类。这就要追溯到创建executor的地方了。
位置在
org.apache.ibatis.session.defaults.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) interceptorChain.pluginAll(executor);
    return executor;
  }

从中可以看到,由于我们用的是默认的executorType,所以应该创建的是SimpleExecutor,并且我们没有关闭cacheEnable,所以会在executor外面包一层CachingExecutor.

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

这是CachingExecutor的构造方法。由此可见delegate对象就是SimpleExecutor(在这个场景而言,其他情况为相对应的Executor)
那我们再回过头来看executor的query方法。
这里的query实现方法应该是cachingExecutor的query方法。

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

第一个参数ms上一节有提到,是所要执行sql的各项配置环境。第二个参数是执行sql的参数,第三个是selectList是的偏移量和大小的设置。最后一个是对返回结果的处理方法。
看这个方法的逻辑。从ms中拿出BoundSql,boundSql中包括了sql的内容(select XX from XXX where XX=?之类的)已经sql的所需参数的信息。
再通过这些参数创建一个缓存的key,然后根据这些属性再继续调用包含key的query方法。

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

这个方法也比较简单,先去取缓存,取得到就去缓存拿,取不到就调用真正的执行器去执行sql。(这里的缓存是二级缓存,暂且不讲)
看到这个delegate的query方法就知道去执行了SimpleExecutor里的query方法了。但实际上SimpleExecutor是没有query方法的,这里执行的query方法是其父类BaseExecutor的query方法。

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) throw new ExecutorException("Executor was closed.");
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      deferredLoads.clear(); // issue #601
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        clearLocalCache(); // issue #482
      }
    }
    return list;
  }

看到这个方法又去拿了一次缓存,其实这里是一级缓存,也暂且不讲。这里的真正实现是queryFromDatabase的doQuery方法,而这个doquery方法,就是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();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

这里拿到Configuration然后再创建statement,statement是什么,参考第一节的jdbc连接数据库方法。(是不是感觉接近真相了)
然后执行handler的query方法。
这个方法具体又是怎么操作的呢?下节分析。

展开阅读全文

没有更多推荐了,返回首页