MyBatis配置文件mybatis-config.xml中的节点settings中有一项配置如下:
"defaultExecutorType" value="SIMPLE" />
配置的是MyBatis在运行过程中默认的执行器Executor,此项配置的默认值就是SIMPLE,指向就是接口Executor的实现类SimpleExecutor。
这些实现类为接口Executor的策略簇,实现了不同的执行器策略:
SimpleExecutor:普通的执行器
BatchExecutor:批处理执行器
ReuseExecutor:预处理语句重用执行器
MyBatis核心类Configuration类似于策略模式中的Context,区别于Context就是:Context维系是的传入的策略对象;Configuration是根据传入的策略对象类型,生产相应的策略对象,代码如下:
// 配置文件中setting属性为defaultExecutorType的对应Configuration属性
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
// 根据默认的执行器类型,生成相应的执行器对象
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
// 可指定执行器类型,生成相应的执行器对象
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;
}
执行器对象的使用者是接口的SqlSessionFactory的默认实现类DefaultSqlSessionFactory,用于生成SqlSession,代码如下:
// 指定执行器类型,事务隔离级别和事务是否自动提交,从数据源中生成SqlSession
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);
// 调用Configuration的newExecutor(Transaction transaction,ExecutorType execType)生成执行器对象
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();
}
}
模板方法模式一般是在抽象类中定义执行流程,具体的执行过程:抽象方法(一个或多个)由子类完成。
上面Executor的继承关系图中可以看到,接口Executor有抽象接口BaseExecutor,其中以do开头的方法都符合模板方法设计模式,简单的分析可以看下面的代码分析:
// 查询
@Override
public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 调用query方法
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@SuppressWarnings("unchecked")
@Override
public List 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 list;
try {
queryStack++;
list = resultHandler == null ? (List) 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();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// 由上面的方法调用,子类实现此方法
protected abstract List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;