在mybatis的ExecutorType中,執行sql有三種執行模式,分別為
SIMPLE
REUSE
BATCH
這三種模式分別對應着三種執行器
SimpleExecutor、ReuseExecutor、BatchExecutor
1.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
}
}
SimpleExecutor是每次都會關閉statement,意味着下一次使用需要重新開啟statement。
2.ReuseExecutor
@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
}
ReuseExecutor不會關閉statement,而是把statement放到緩存中。緩存的key為sql語句,value即為對應的statement。也就是說不會每一次調用都去創建一個 Statement 對象,而是會重復利用以前創建好的(如果SQL相同的話),這也就是在很多數據連接池庫中常見的 PSCache 概念 。
3.BatchExecutor
@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(stmt);//fix Issues 322
BatchResult batchResult = batchResultList.get(last);
batchResult.addParameterObject(parameterObject);
} else {
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt); //fix Issues 322
currentSql = sql;
currentStatement = ms;
statementList.add(stmt);//否則創建statement並存入
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
// handler.parameterize(stmt);
handler.batch(stmt);//僅僅是存入批處理參數而不執行
return BATCH_UPDATE_RETURN_VALUE;//始終返回一個常量
}
總結
SimpleExecutor是一種常規執行器,每次執行都會創建一個statement,用完后關閉。
ReuseExecutor是可重用執行器,將statement存入map中,操作map中的statement而不會重復創建statement。
BatchExecutor是批處理型執行器,doUpdate預處理存儲過程或批處理操作,doQuery提交並執行過程。
性能對比
SimpleExecutor 比 ReuseExecutor 的性能要差 , 因為 SimpleExecutor 沒有做 PSCache。為什么做了 PSCache 性能就會高呢 , 因為當SQL越復雜占位符越多的時候預編譯的時間也就越長,創建一個PreparedStatement對象的時間也就越長。猜想中BatchExecutor比ReuseExecutor功能強大性能高,實際上並非如此,BatchExecutor是沒有做PSCache的。BatchExecutor 與 SimpleExecutor 和 ReuseExecutor 還有一個區別就是 , BatchExecutor 的事務是沒法自動提交的。因為 BatchExecutor 只有在調用了 SqlSession 的 commit 方法的時候,它才會去執行 executeBatch 方法。
如何在項目中設置這些模式
mybatis+spring中ExecutorType的使用
<!--配置一個可以進行批量執行的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
```