我们知道mybatis通过门面模式给我们提供了一个统一的增删改查的会话SqlSession。但是呢它就像服务员一样只负责点菜并不负责做菜,真正做菜的是执行器。那mybatis中有哪些执行器呢?
mybatis中的执行器大概有这么多:Executor、CachingExecutor、BaseExecutor、SimpleExecutor、ReuseExecutor、BatchExecutor等。看起来好像很多其实很简单,咱们往下走。
我们通过最简单的一个查询来看看这些货到底是什么关系:
List
sqlSession默认实现是DefaultSqlSession,所以我们进到这个方法:
public List selectList(String statement) {
return this.selectList(statement, (Object)null);
}
继续进到这个方法:
public List selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
继续:
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
//注意 这里真正干活的是this.executor 而这个executor默认实现是CachingExecutor
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
至此,我们知道了真正干活的是这个CachingExecutor。顾名思义这是个缓存相关的执行器,它就是大名鼎鼎的二级缓存执行器。里边实现了mybatis的二级缓存相关实现。但是本篇文章并不详细解释。我们进到CachingExecutor的query方法:
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
//进到这个重载方法
return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
继续:
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
this.flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, boundSql);
//这里就是去查询二级缓存了
List list = (List)this.tcm.getObject(cache, key);
if (list == null) {
//如果没有查询到 那么就去执行this.delegate的query方法
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
}
return list;
}
}
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
那么这个this.delegate是啥呢?它就是BaseExecutor,正式mybatis里边一级缓存的执行器。那么我们继续:
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 (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
//这里就是在查询一级缓存了
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//如果没有查询到 那么就真正的去查询数据库了
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
DeferredLoad deferredLoad = (DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
我们继续进到queryFromDatabase方法:
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//进到这个方法
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
protected abstract List doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;
我们发现,咦?咋是个抽象的方法呢?那么他的实现方法在哪儿呢?哈哈哈 BaseExecutor常用的有三个现实,正是SimpleExecutor ReuseExecutor BatchExecutor。通过名字也能看出来这个仨分别是简单 重用和批处理执行器。具体的操作数据库封装JDBC都是他们干的。行棋至此,我们mybatis中的执行器整体架构已经出来了,让我们画个图来总结一下吧!