mybatis源码解析(4)

来源:互联网 发布:pyqt linux 安装 arm 编辑:程序博客网 时间:2024/05/01 03:05

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方法。
这个方法具体又是怎么操作的呢?下节分析。

0 0