Mybatis之Executor执行器
2021-03-30 本文已影响0人
engineer_tang
Executor执行器接口定义如下:
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
boolean isCached(MappedStatement ms, CacheKey key);
void clearLocalCache();
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
Transaction getTransaction();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
执行器子类实现结构图如下:
image.png
1. CachingExecutor类
这里用到了装饰器模式,抽象构件角色是BaseExecutor,具体构件角色是SimpleExecutor、ReuseExecutor、BatchExecutor,这里没有抽象装饰角色,具体装饰角色是CachingExecutor,通过该模式完成了缓存功能的实现。
2. SimpleExecutor和ReuseExecutor对比
SimpleExecutor是默认的执行器,每次执行都会创建一个Statement对象,使用完成会调用closeStatement方法比比使用完的Statement。如下所示:
image.png
而Reuse使用完成不会关闭Statement,而是会存入自己维护的HashMap结构的statementMap容器中,方便下次复用。
image.png
请看ReuseExecutor类的如下代码:
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);
applyTransactionTimeout(stmt);
} else {
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
putStatement(sql, stmt);
}
handler.parameterize(stmt);
return stmt;
}
private boolean hasStatementFor(String sql) {
try {
return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
} catch (SQLException e) {
return false;
}
}
private Statement getStatement(String s) {
return statementMap.get(s);
}
private void putStatement(String sql, Statement stmt) {
statementMap.put(sql, stmt);
}
从如上代码可以知道,每次获取Statement对象时,会先调用hasStatementFor方法看statementMap容器中是否有可直接使用的Statement对象,如果没有就新创建一个,并且缓存到statementMap容器中。