mybatis执行Sql的核心类是Executor,其结构如图所示,核心是BaseExecutor,继承自BaseExecutor的有BatchExecutor、ClosedExecutor、ReuseExecutor、与SimpleExecutor四个类,分别对应着执行器的四个类型。
在配置文件中可以定义的执行类型如下图所示。
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}
ExecutorType定义了的三种Executor类型。
同时,继承子Executor的类有CachingExecutor,该执行器实现了mybatis缓存。但是具体的sql执行等仍然是委托给上面提到的三个(Closed未用)执行器。
以SqlSession的SelectList举例了解执行过程。
首先执行位于DefaultSqlSession的selectList
@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为cachingExecutor,该执行器将具体的执行功能委托给BaseExecutor的基类去完成,具体的用哪个Executor,还需要用户在配置文件中定义,首先从Configuration实例中获取mybatis映射语句,然后调用CachingExecutor执行query
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject); //生成sql
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); //缓存键值
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //进一步处理
}
mybatis支持缓存,根据sql,参数等信息首先查询缓存,若没有命中的话才会执行数据库查询,接着:
@Override
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) { //如果定义缓存,则从缓存中fetch
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 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //若没有定义缓存,则直接查询数据库
}
delegate.<E> query(***);语句将数据库查询委托给BaseExecutor的具体实现,也就是BATCH、SIMPLE、REUSE中的任何一个(在配置文件中指定)。这里以Simple,无缓存为例(最简单)。紧接着或调用BaseExecutor中的query方法。
BaseExecutor.java
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); //生成缓存主键
return query(ms, parameter, rowBounds, resultHandler, key, boundSql); //调用含有缓存功能的query方法
}
最终会执行BaseExecutor的doQuery方法。该方法,该方法是工厂方法,在具体的类中有着不同的实现。在SimpleExecutor中的实现如下所示:
@Override
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);
}
}
stmt是javasql中的类,感觉和执行sql更接近了。 是StatementHandler负责生成最终要执行的sql代码的类。configuration.newStatementHandler()方法用来生成StatementHandler。
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
生成的是RoutingStatementHandler,也是一个委托模式吧,图中是其继承层次关系。
RoutingStatementHandler把具体的实现委托给BaseStatementHandler的基类完成。interceptorChain.pluginAll(statementHandler)用于mybatis的插件功能,用所有的插件对此接口生成代理,以便对statementHandler接口的所有方法进行拦截(具体内容见职责链模式与动态代理模式)。
至此,Executor的所有工具已经完成剩下的是StatementHandler的职责。