Executor功能概述
每一个sql语句的执行都会先到Executor执行器中在调用相应StatementHandler执行jdbc操作。源码如下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(); //调用StatmentHandler,通过控制器调用jdbc相关操作
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
Executor继承体系如下
Executor 执行器接口,它有两个实现类,分别是BaseExecutor和 CachingExecutor。
BaseExecutor :是一个抽象类,这种通过抽象的实现接口的方式是适配器设计模式之接口适配的体现,是 Executor
的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor
的子类有三个,分别是SimpleExecutor、ReuseExecutor和BatchExecutor。
SimpleExecutor: 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个
Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment
对象)
ReuseExecutor: 可重用执行器,这里的重用指的是重复使用Statement,它会在内部使用一个 Map 把创建的
Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在
Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement
对象,并将其缓存起来。每个SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor
上的Statement 作用域是同一个 SqlSession。
BatchExecutor: 批处理执行器,用于将多个SQL一次性输出到数据库
CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在,就返回;如果不存在,再委托给 Executor delegate
去数据库中取,delegate 可以是上面任何一个执行器,默认是simpleexecutor
Executor创建过程源码分析
- 创建SqlSession时,可以指定Executor类型,mybatis中ExecutorType枚举类来指定,ExecutorType源码如下,分别指定BaseExecutor下面三个实现类
/**
* 执行器类型
*
* @author Clinton Begin
*/
public enum ExecutorType {
/**
* {@link org.apache.ibatis.executor.SimpleExecutor}
*/
SIMPLE,
/**
* {@link org.apache.ibatis.executor.ReuseExecutor}
*/
REUSE,
/**
* {@link org.apache.ibatis.executor.BatchExecutor}
*/
BATCH
}
2. 根据传递ExecutorType类型可以指定Executor种类,默认不传参就是SimpleExecutor
SqlSession sqlsession=sqlsessionFactory.openSession();
//SqlSession
sqlsession=sqlsessionFactory.openSession(ExecutorType.REUSE);
3. DefaultSqlSessionFactory中创建执行器,源码如下
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获得 Environment 对象
final Environment environment = configuration.getEnvironment();
// 创建 Transaction 对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建 Executor 对象
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// 如果发生异常,则关闭 Transaction 对象
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
4. 下面看执行器具体创建流程configuration.newExecutor(tx, execType)
/**
* 创建 Executor 对象
*
* @param transaction 事务对象
* @param executorType 执行器类型
* @return Executor 对象
*/
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 获得执行器类型
executorType = executorType == null ? defaultExecutorType : executorType; // 使用默认
executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 使用 ExecutorType.SIMPLE
// 创建对应实现的 Executor 对象
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);
}
// 如果开启缓存,创建 CachingExecutor 对象,进行包装
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 应用插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}