Mybatis#BaseExecutor原始碼解析
BaseExecutor是Executor的一個子類,是一個抽象類,實現介面Executor的部分方法,並提供了三個抽象方法
- doUpdate
- doFlushStatements
- doQuery
在他的子類SimpleExecutor、ReuseExecutor和BatchExecutor中實現。
BaseExecutor也算是一個模板類,幾個抽象方法在子類中實現

具體選用哪個子類實現,可以在Mybatis的配置檔案中進行配,配置如下:
<settings> <setting name="defaultExecutorType" value="REUSE"/> <!--SIMPLE、REUSE、BATCH--> </settings>
配置之後在Configuration類中的newExecutor()函式會選擇具體使用的子類,實現如下:
public Executor newExecutor(Transaction transaction, ExecutorType 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); } //cacheEnabled預設是true,所以還是會使用CachingExecutor,不知何意 if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
BaseExecutor原始碼解析
/** * @author Clinton Begin */ public abstract class BaseExecutor implements Executor { protected Transaction transaction; protected Executor wrapper; protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads; //快取 永久快取本地快取 protected PerpetualCache localCache; protected PerpetualCache localOutputParameterCache; //mybatis配置資訊 protected Configuration configuration; //查詢堆疊 protected int queryStack = 0; private boolean closed; protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>(); this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; this.wrapper = this; } public void close(boolean forceRollback) { try { try { rollback(forceRollback); } finally { if (transaction != null) transaction.close(); } } catch (SQLException e) { // Ignore.There's nothing that can be done at this point. log.warn("Unexpected exception on closing transaction.Cause: " + e); } finally { transaction = null; deferredLoads = null; localCache = null; localOutputParameterCache = null; closed = true; } } //SqlSession的update/insert/delete會呼叫該方法 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); } public List<BatchResult> flushStatements() throws SQLException { return flushStatements(false); } public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException { if (closed) throw new ExecutorException("Executor was closed."); return doFlushStatements(isRollBack); } //SqlSession.selectList會呼叫此方法 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //得到繫結sql BoundSql boundSql = ms.getBoundSql(parameter); //建立快取key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); //查詢 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } @SuppressWarnings("unchecked") public <E> List<E> 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."); //先清區域性快取,再查詢,但僅當查詢堆疊為0時才清,為了處理遞迴呼叫 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { //加一,這樣遞迴呼叫到上面的時候就不會再清區域性快取了 queryStack++; //根據cachekey從localCache去查 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { //如果查到localCache快取,處理localOutputParameterCache 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(); } //清空延遲載入佇列 deferredLoads.clear(); // issue #601 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { //如果是statement,清本地快取 clearLocalCache(); // issue #482 } } return list; } //延遲載入 public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) { if (closed) throw new ExecutorException("Executor was closed."); DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType); //如果能載入則立即載入,否則加入到延遲載入佇列中 if (deferredLoad.canLoad()) { deferredLoad.load(); } else { //這裡怎麼又new了一個新的,效能有點問題 deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType)); } } //建立快取key public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) throw new ExecutorException("Executor was closed."); CacheKey cacheKey = new CacheKey(); //MyBatis 對於其 Key 的生成採取規則為:[mappedStementId + offset + limit + SQL + queryParams + environment]生成一個雜湊碼 cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); for (int i = 0; i < parameterMappings.size(); i++) { // mimic DefaultParameterHandler logic ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } return cacheKey; } public void commit(boolean required) throws SQLException { if (closed) throw new ExecutorException("Cannot commit, transaction is already closed"); clearLocalCache(); flushStatements(); if (required) { transaction.commit(); } } public void rollback(boolean required) throws SQLException { if (!closed) { try { clearLocalCache(); flushStatements(true); } finally { if (required) { transaction.rollback(); } } } } //清空本地快取,一個map結構 public void clearLocalCache() { if (!closed) { localCache.clear(); localOutputParameterCache.clear(); } } //子類中實現 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 void closeStatement(Statement statement) { if (statement != null) { try { statement.close(); } catch (SQLException e) { // ignore } } } //處理儲存過程的out引數 private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { final Object cachedParameter = localOutputParameterCache.getObject(key); if (cachedParameter != null && parameter != null) { final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter); final MetaObject metaParameter = configuration.newMetaObject(parameter); for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { final String parameterName = parameterMapping.getProperty(); final Object cachedValue = metaCachedParameter.getValue(parameterName); metaParameter.setValue(parameterName, cachedValue); } } } } } //從資料庫中查 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //向快取中放入佔位符 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { //清除佔位符 localCache.removeObject(key); } //加入快取 localCache.putObject(key, list); //如果是儲存過程,OUT引數也加入快取 if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; } protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } } public void setExecutorWrapper(Executor wrapper) { this.wrapper = wrapper; } //延遲載入 private static class DeferredLoad { private final MetaObject resultObject; private final String property; private final Class<?> targetType; private final CacheKey key; private final PerpetualCache localCache; private final ObjectFactory objectFactory; private final ResultExtractor resultExtractor; public DeferredLoad(MetaObject resultObject, String property, CacheKey key, PerpetualCache localCache, Configuration configuration, Class<?> targetType) { // issue #781 this.resultObject = resultObject; this.property = property; this.key = key; this.localCache = localCache; this.objectFactory = configuration.getObjectFactory(); this.resultExtractor = new ResultExtractor(configuration, objectFactory); this.targetType = targetType; } //快取中找到,且不為佔位符,代表可以載入 public boolean canLoad() { return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER; } //載入 public void load() { @SuppressWarnings( "unchecked" ) // we suppose we get back a List List<Object> list = (List<Object>) localCache.getObject(key); Object value = resultExtractor.extractObjectFromList(list, targetType); resultObject.setValue(property, value); } } }