一、SimpleExecutor
SimpleExecutor繼承BaseExecutor
主要實現:doUpdate、doQuery、doFlushStatements
可以看代碼主要是:
1、獲取聲明處理類:StatementHandler handler
2、獲取聲明類:stmt = prepareStatement(handler, ms.getStatementLog());
3、處理聲明,執行SQL處理
二、ReuseExecutor
與SimpleExecutor不同的是:重用聲明
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
if (hasStatementFor(sql)) {
stmt = getStatement(sql);
} else {
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
putStatement(sql, stmt);
}
handler.parameterize(stmt);
return stmt;
}
SQL語句一樣的,就用同樣的聲明。不過這個好像也僅僅是同一個session內的有效。
三、BatchExecutor
先看update
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
final Configuration configuration = ms.getConfiguration();
final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
final BoundSql boundSql = handler.getBoundSql();
final String sql = boundSql.getSql();
final Statement stmt;
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
int last = statementList.size() - 1;
stmt = statementList.get(last);
BatchResult batchResult = batchResultList.get(last);
batchResult.addParameterObject(parameterObject);
} else {
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection);
currentSql = sql;
currentStatement = ms;
statementList.add(stmt);
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
handler.parameterize(stmt);
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
if
(sql.equals(currentSql) && ms.equals(currentStatement))
表明同一個SQL語句使用同一個申明,應用場景很簡單,就是我們的批量刪除和批量插入,在沒有參數的SQL語句他們就是一樣的,不一樣的只是參數而已。具體參數處理在StatementHandler裏面去設置的。也是同一個session內的批量操作。是不是很奇怪沒有提交?看完查詢再說:
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
重點flushStatements,爲什麼這裏會做這件事呢?因爲在同一session裏面如果又是批量操作,又是查詢的話,那麼就必須保證批量操作數據提交上去了。也就是爲什麼有這個,這個方法主要的事情歸結到doFlushStatements,就是批量更新提交。查詢有提交,批量更新那個怎麼沒有提交?在sqlsession裏面commit調用BaseExecutor裏面commit:
public void commit(boolean required) throws SQLException {
if (closed) throw new ExecutorException("Cannot commit, transaction is already closed");
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();
}
}
flushStatements();注意使用批量的時候,如果不開啓批量模式,是沒有使用批量更新的,使用sessionFactory.openSession(ExecutorType.BATCH,
false);
網上大部分例子都沒有正確使用批量更新,因爲mybatis默認是SimpleExecutor執行器
四、CachingExecutor
緩存執行器,顧名思義跟緩存有關係,這裏的緩存是全局緩存,configuration裏面的cacheEnabled參數決定,默認爲true
也就是默認是開啓全局緩存,但是隻是這裏開啓就可以嗎?詳細看看CachingExecutor這個類:
先看創建這個類:
public CachingExecutor(Executor delegate) {
this(delegate, false);
}
public CachingExecutor(Executor delegate, boolean autoCommit) {
this.delegate = delegate;
this.autoCommit = autoCommit;
}
裝飾模式,也就是說緩存執行器,增強了其他的執行器,不同的是他先執行緩存處理。(以後需要加緩存時可以借鑑)
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
更新先flush緩存
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) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
if (!dirty) {
cache.getReadWriteLock().readLock().lock();
try {
@SuppressWarnings("unchecked")
List<E> cachedList = (List<E>) cache.getObject(key);
if (cachedList != null) return cachedList;
} finally {
cache.getReadWriteLock().readLock().unlock();
}
}
List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
return list;
}
}
return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
查詢重點:
Cache cache = ms.getCache(); 看mapper上配置緩存沒有,如果有執行緩存邏輯,所以默認全局緩存開啓後,每個mapper上必須配置是否使用緩存,緩存纔有效。這個緩存在MappedStatement上,所以是全局的,非僅僅在session內有效。