经历了上一篇mybaits的基础架构部分的configuration的源码解析,也深感自身功力不足,也可能是configuration是复杂基础组件,一套下来感觉有点恶心吃不消,后面总算是有模有样的缕清了关系。言归正传,依旧继续上一个例子,这篇来解析下Executor。
public int update(int id) {
SqlSession session = SQLSessionFactory.getSessoinFactory().openSession();
int i = session.update(namespace+"updateOne",id);
session.commit();
session.close();
return i;
}
SqlSession我们已经解析过,Executor是它包装的工作单元,如上面的close、commit、update等方法,实际上是由Executor来执行的。Executor同样是一个接口,同样可以理解为不同的Executor实现不同的策略。
Executor的两个实现子类:
update方法实际被Sqlsession用于update、delete,query被用作selectone、selectlist等,以update方法为例,看下BaseExecutor中的实现:
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());//将信息存入错误上下文
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();//清空缓存
return doUpdate(ms, parameter);//委托方法
}
我们没有直接看到update操作的逻辑,在update方法中,委托给了doUpdate方法执行,而诸如doUpdate的这些方法则是抽象方法:
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
这是一种模板方法模式,baseExecutor实现共性的操作,而具体的操作则由子类完成。而Executor接口的另一个子类CachingExecutor又如何实现update的:
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);//交给委托对象执行
}
交给一个委托对象delegate执行update,这个委托对象就是Executor对象,而CachingExecutor本身是一个Executor的装饰器:
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);//回调委托对象设置装饰器
}
CachingExecutor不是baseExecutor的子类而是兄弟类,因此他肯定是对baseExecutor的子类进行包装,什么时候使用何种executor?返回它的创建者(configuration)就知道了:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;//如果没有传入类型,则使用默认类型
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;//如果默认类型为空,则使用simpleExecutor
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);//批处理executor
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);//重用executor
} else {
executor = new SimpleExecutor(this, transaction);//简单executor
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);//缓存executor
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
加上baseExecutor的子类,一共有4种executor,下面我们一个个分析他们即可。根据上面的注释,默认情况下,会优先使用默认类型,而默认类型就是XMLConfigBuilder从配置文件中sql节点的配置属性解析映射而来的。如果没有设置,那么默认都是使用simple类型:configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
还有一种情况,就是传入的executor类型会是什么?结合之前的流程,我们知道一个Sqlsession中会持有一个executor,但是Sqlsession并不负责executor的创建,因此应该从应用程序中update的上一个步骤来入手:SqlSession session = SQLSessionFactory.getSessoinFactory().openSession();前几个例子和这里因为我写了一个工具类来获取sessionFactory,所以实际上我们还是得先研究sessionFactory:
sessionFactory是一个接口,这个接口限定openSession返回的session必需是从连接或数据源创建的:
/**
* Creates an {@link SqlSession} out of a connection or a DataSource
* //创建一个必需是从连接或数据源创建的SqlSession
* @author Clinton Begin
*/
public interface SqlSessionFactory {
SqlSession openSession();//实际用到的只有这两个方法
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);//这个接口方法及下面的方法均是用户管理方法
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
它的两个实现子类分别是:
现在聚焦DefaultSqlSessionFactory,了解他是如何创建SqlSession的。上面说到,Sqlsession不负责创建executor,那么executor也是由factory负责创建并传入给session的。创建session都是通过下面两个核心方法产生,一个通过数据源产生,另一个直接由连接对象产生,其实大同小异,数据源只是对连接做了一个封装而已。关键是根据传入的executor类型参数来决定创建哪一种executor,而他们最终都是创建DefaultSqlSession并返回:
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);//传入类型创建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();
}
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);//传入类型创建executor
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
从下面的方法调用说明,Executor的类型跟随configuration默认配置:
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
如何修改默认设置?参照官方说明,在setting中配置如下条目设置:
最后,限于篇幅,上面提到的4种executor另做分解。总结一下:执行器Executor是一个接口,有四种类型的子类执行器,可通过配置文件的setting进行设定,默认使用simple类型,应用程序中可以通过manager创建所需类型的执行器的SqlSession。
本篇的类关系图总结如下: