Pre
MyBatis源碼-深入理解MyBatis Executor的設計思想
工程部分見
MyBatis源碼- SqlSession門面模式 & selectList 源碼解析
實際中,我們都是面向SqlSession編程的,不會直接調用Executor來執行業務邏輯,這裏我們僅僅是爲了深入瞭解下Executor體系架構才這麼搞的,切記。
Executor 執行器
接口繼承關係
這裏我們重點看下Executor的 三個實現子類。
分別是:SimpleExecutor(簡單執行器)、ReuseExecutor(重用執行器)、BatchExecutor(批處理執行器)。
ReuseExecutor(重用執行器)
迴歸下JDBC中的 Statement , 再和MyBatis 所封裝的 對比一下
PreparedStatement 支持預編譯參數
MyBatis的ReuseExecutor就是利用了JDBC Statement的這個特點 來處理的。
入門小demo
@Test
public void testReuseExecutor() throws SQLException {
// 通過factory.openSession().getConnection()實例化JdbcTransaction ,用於構建ReuseExecutor
jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
// 映射SQL
ms = configuration.getMappedStatement("com.artisan.UserMapper.selectByid");
// 實例化ReuseExecutor
ReuseExecutor executor = new ReuseExecutor(configuration, jdbcTransaction);
// 調用doQuery執行查詢
List<User> userList = executor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
System.out.println(userList.get(0));
List<User> userList2 = executor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
System.out.println(userList2.get(0));
}
執行結果
可以看到 相同的SQL語句 會緩存對應的PrepareStatement , 緩存的生命週期: 會話有效期
源碼實現
Key 是 sql , Value 是 Statement
執行過程:
executor.doQuery ----> prepareStatement(handler, ms.getStatementLog())
---------> 見下方源碼
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;
}
先判斷本地緩存statementMap是否有數據,有的話從statementMap獲取,沒有的話建立Statement,並存入本地緩存statementMap 。
注意這個緩存的聲明週期 是僅限於本次會話。 會話結束後,這些緩存都會被銷燬掉。
區別於SimpleExecutor的實現,多了個本地緩存。 推薦使用ReuseExecutor 。