mybatis源码阅读-执行器Executor(四)
说明
前面二看到了 sqlSession最终是找到MapperStatement然后委托给Executer执行的 Executer到底做了什么
接口定义
public interface Executor { ResultHandler NO_RESULT_HANDLER = null; int update(MappedStatement var1, Object var2) throws SQLException; <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException; <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException; <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException; List<BatchResult> flushStatements() throws SQLException; void commit(boolean var1) throws SQLException; void rollback(boolean var1) throws SQLException; CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4); boolean isCached(MappedStatement var1, CacheKey var2); void clearLocalCache(); void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5); Transaction getTransaction(); void close(boolean var1); boolean isClosed(); void setExecutorWrapper(Executor var1); }
类图
Executor各个实现
ClosedExecutor
org.apache.ibatis.executor.loader.ResultLoaderMap 中的一个内部静态类
private static final class ClosedExecutor extends BaseExecutor { public ClosedExecutor() { super((Configuration)null, (Transaction)null); } public boolean isClosed() { return true; } protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException { throw new UnsupportedOperationException("Not supported."); } protected List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { throw new UnsupportedOperationException("Not supported."); } protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { throw new UnsupportedOperationException("Not supported."); } protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException { throw new UnsupportedOperationException("Not supported."); } }
没有具体实现 我们不会用到
简单SimpleExecutor
每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。(可以是Statement或PrepareStatement对象)
public class SimpleExecutor extends BaseExecutor { public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; int var6; try { //获得configuration Configuration configuration = ms.getConfiguration(); //根据configuration获得对应的StatementHandler 后面讲 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler) null, (BoundSql) null); stmt = this.prepareStatement(handler, ms.getStatementLog()); var6 = handler.update(stmt); } finally { //释放Statement this.closeStatement(stmt); } return var6; } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Connection connection = this.getConnection(statementLog); Statement stmt = handler.prepare(connection, this.transaction.getTimeout()); handler.parameterize(stmt); return stmt; } }
可以看到finally会关闭Statement
复用ReuseExecutor
Statement会根据sql语句进行保存 相同sql语句达到复用 避免多次编译
public class ReuseExecutor extends BaseExecutor { //保存Statement key为sql语句 private final Map<String, Statement> statementMap = new HashMap(); public ReuseExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null); //构建Statemetn Statement stmt = this.prepareStatement(handler, ms.getStatementLog()); return handler.update(stmt); } public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { Iterator i$ = this.statementMap.values().iterator(); while(i$.hasNext()) { Statement stmt = (Statement)i$.next(); this.closeStatement(stmt); } //清空缓存 this.statementMap.clear(); return Collections.emptyList(); } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { BoundSql boundSql = handler.getBoundSql(); //获得sql语句 String sql = boundSql.getSql(); Statement stmt; //判断是否有缓存 如果有重缓存取 if (this.hasStatementFor(sql)) { stmt = this.getStatement(sql); this.applyTransactionTimeout(stmt); } else { Connection connection = this.getConnection(statementLog); //如果没有创建Statement 并仿佛缓存 stmt = handler.prepare(connection, this.transaction.getTimeout()); this.putStatement(sql, stmt); } handler.parameterize(stmt); return stmt; } private boolean hasStatementFor(String sql) { try { return this.statementMap.keySet().contains(sql) && !((Statement)this.statementMap.get(sql)).getConnection().isClosed(); } catch (SQLException var3) { return false; } } private Statement getStatement(String s) { return (Statement)this.statementMap.get(s); } private void putStatement(String sql, Statement stmt) { this.statementMap.put(sql, stmt); } }
Statement什么时候释放 doFlushStatements为父类的抽象方法 父类再rollback和commit 会调用doFlushStatements()(模板方法模式)
BaseExecutor代码
public void commit(boolean required) throws SQLException { if (this.closed) { throw new ExecutorException("Cannot commit, transaction is already closed"); } else { this.clearLocalCache();
//会里面会调用this.doFlushStatements() this.flushStatements(); if (required) { this.transaction.commit(); } } }
批量BatchExecutor
public class BatchExecutor extends BaseExecutor { public static final int BATCH_UPDATE_RETURN_VALUE = -2147482646; private final List<Statement> statementList = new ArrayList(); private final List<BatchResult> batchResultList = new ArrayList(); //上一次sql private String currentSql; //上一次Statement private MappedStatement currentStatement; public BatchExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null); BoundSql boundSql = handler.getBoundSql(); String sql = boundSql.getSql(); Statement stmt; //当前sql语句是否与上一次sql语句一样 如果一样同时 当前Statement是否与上一次Statement一样 if (sql.equals(this.currentSql) && ms.equals(this.currentStatement)) { //取出最后一个Statement int last = this.statementList.size() - 1; stmt = (Statement)this.statementList.get(last); this.applyTransactionTimeout(stmt); handler.parameterize(stmt); //获得BatchResult 增加参数inset table value('1111','2222',....) BatchResult batchResult = (BatchResult)this.batchResultList.get(last); batchResult.addParameterObject(parameterObject); } else { //不存在在则新增Statement Connection connection = this.getConnection(ms.getStatementLog()); stmt = handler.prepare(connection, this.transaction.getTimeout()); handler.parameterize(stmt); this.currentSql = sql; this.currentStatement = ms; this.statementList.add(stmt); this.batchResultList.add(new BatchResult(ms, sql, parameterObject)); } // 将sql以addBatch()的方式,添加到Statement中(该步骤由StatementHandler内部完成) handler.batch(stmt); return -2147482646; } /** * 负责批量执行 * @param isRollback * @return * @throws SQLException */ public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { boolean var17 = false; Statement stmt; List var21; Iterator i$; label168: { ArrayList var20; try { var17 = true; ArrayList results = new ArrayList(); if (isRollback) { var21 = Collections.emptyList(); var17 = false; break label168; } int i = 0; //批量执行 for(int n = this.statementList.size(); i < n; ++i) { stmt = (Statement)this.statementList.get(i); this.applyTransactionTimeout(stmt); BatchResult batchResult = (BatchResult)this.batchResultList.get(i); try { batchResult.setUpdateCounts(stmt.executeBatch()); MappedStatement ms = batchResult.getMappedStatement(); List<Object> parameterObjects = batchResult.getParameterObjects(); KeyGenerator keyGenerator = ms.getKeyGenerator(); if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) { Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator)keyGenerator; jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects); } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { Iterator i$ = parameterObjects.iterator(); while(i$.hasNext()) { Object parameter = i$.next(); keyGenerator.processAfter(this, ms, stmt, parameter); } } } catch (BatchUpdateException var18) { StringBuilder message = new StringBuilder(); message.append(batchResult.getMappedStatement().getId()).append(" (batch index #").append(i + 1).append(")").append(" failed."); if (i > 0) { message.append(" ").append(i).append(" prior sub executor(s) completed successfully, but will be rolled back."); } throw new BatchExecutorException(message.toString(), var18, results, batchResult); } results.add(batchResult); } var20 = results; var17 = false; } finally { if (var17) { Iterator i$ = this.statementList.iterator(); while(i$.hasNext()) { Statement stmt = (Statement)i$.next(); this.closeStatement(stmt); } this.currentSql = null; //释放 this.statementList.clear(); //释放 this.batchResultList.clear(); } } i$ = this.statementList.iterator(); //释放 while(i$.hasNext()) { stmt = (Statement)i$.next(); this.closeStatement(stmt); } this.currentSql = null; this.statementList.clear(); this.batchResultList.clear(); return var20; } i$ = this.statementList.iterator(); while(i$.hasNext()) { stmt = (Statement)i$.next(); this.closeStatement(stmt); } this.currentSql = null; this.statementList.clear(); this.batchResultList.clear(); return var21; } }
if (sql.equals(this.currentSql) && ms.equals(this.currentStatement))看出 如果sql一样同时是连续的 则是使用同一个statement
比如 aabb生成2个statement abba会生成三个statement 主要作用是减少sql预编译时间
缓存CachingExecutor
public class CachingExecutor implements Executor { private Executor delegate; public CachingExecutor(Executor delegate) { this.delegate = delegate; delegate.setExecutorWrapper(this); } public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); //根据sql和参数算出缓存key CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql); return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } 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) { //是否清除缓存 this.flushCacheIfRequired(ms); //是否应用缓存 if (ms.isUseCache() && resultHandler == null) { // this.ensureNoOutParams(ms, parameterObject, boundSql); //如果缓存拿不到 则通过delegate重新执行query List<E> list = (List)this.tcm.getObject(cache, key); if (list == null) { 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); } }
装饰者模式判断是否有缓存 如果没有则委托给delegate执行 拿到结果再将结果缓存
Executor的设置
默认为Simple
configuration配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="defaultExecutorType" value="REUSE" /> </settings> </configuration>
openSession
@Override public SqlSession openSession(ExecutorType execType, boolean autoCommit) { return openSessionFromDataSource(execType, null, autoCommit); }