上篇说到 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.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