上一篇对Executor接口进行了大致的分析,这边来针对它的实现进行分析。
现在我们知道,mybatis默认情况下是使用simpleExecutor的,如果你需要修改,有两种方式,一是在setting中配置defualtExecutorType,另一种方式是通过SqlSessionManager指定executorType并创建sqlsession。下面以doUpdate和doQuery方法为例,比较这几种executor的差异,因为executor提供sqlSession的就是这两个核心基础方法。
doUpdate
simpleExecutor:
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());//创建statement
return handler.update(stmt);
} finally {
closeStatement(stmt);//关闭statement,意味着下一次使用需要重新开启statement
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());//创建statement
handler.parameterize(stmt);//将参数存入statement
return stmt;
}
ReuseExecutor:
将statement存入map中:
private final Map<String, Statement> statementMap = new HashMap<String, Statement>();
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);//没有关闭statement
}
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);//如果已缓存statement则取出
applyTransactionTimeout(stmt);
} else {
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
putStatement(sql, stmt);//否则创建statement并存入
}
handler.parameterize(stmt);
return stmt;
}
看看它是怎么映射判断已缓存的statement的:
private boolean hasStatementFor(String sql) {
try {
return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();//sql语句就是key,statement是值
} catch (SQLException e) {
return false;
}
}
BatchExecutor:
public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;//为何?防无限循环
private final List<Statement> statementList = new ArrayList<Statement>();//使用list缓存statement
private final List<BatchResult> batchResultList = new ArrayList<BatchResult>();
private String currentSql;
private MappedStatement currentStatement;
@Override
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)) {//判断当前使用sql和statement是否是上一次的statement和sql
int last = statementList.size() - 1;
stmt = statementList.get(last);//如果是则取出
applyTransactionTimeout(stmt);
handler.parameterize(st