1、Executor
sql執行器,其對應的類全路徑:org.apache.ibatis.executor.Executor。
1.1 Executor類圖
-
Executor 執行器根據介面,定義update(更新或插入)、query(查詢)、commit(提交事務)、rollback(回滾事務)。接下來簡單介紹幾個重要方法:
- int update(MappedStatement ms, Object parameter) throws SQLException 更新或插入方法,其引數含義如下:、 1)MappedStatement ms:SQL對映語句(Mapper.xml檔案每一個方法對應一個MappedStatement物件) 2)Object parameter:引數,通常是List集合。
- < E> List< E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) 查詢方法,其引數含義如下: 1)RowBounds:行邊界,主要值分頁引數limit、offset。 2)ResultHandler resultHandler:結果處理器。
- CacheKey createCacheKey(MappedStatement ms, Object parameterObj, RowBounds bounds, BoundSql bSql) 建立快取Key,Mybatis一二級快取的快取Key,可以看出Key由上述4個引數來決定。 1)BoundSql boundSql:可以通過該物件獲取SQL語句。
-
CachingExecutor 支援結果快取的SQL執行器,注意其設計模式的應用,該類中,會持有Executor的一個委託物件,CachingExecutor關注與快取特定的邏輯,其最終的SQL執行由其委託物件來實現,即其內部的委託物件為BaseExecutor的實現類。
-
BaseExecutor Executor的基礎實現類,該類為抽象類,關於查詢、更新具體的實現由其子類來實現,下面4個都是其子類。
-
SimpleExecutor 簡單的Executor執行器。
-
BatchExecutor 支援批量執行的Executor執行器。
-
ClosedExecutor 表示一個已關閉的Executor。
-
ReuseExecutor 支援重複使用Statement,以SQL為鍵,快取Statement物件。
1.2 建立Executor
在Mybatis中,Executor的建立由Configuration物件來建立,具體的程式碼如下:
Configuration#newExecitor
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType); // @1
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) { // @2
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) { // @3
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor); // @4
return executor;
}
複製程式碼
從上面的程式碼可以看出,Executor的建立由如下三個關鍵點: 程式碼@1:預設的ExecutorType為ExecutorType.SIMPLE,即預設建立的Executory為SimpleExecutor。 程式碼@2:根據executorType的值建立對應的Executory。 程式碼@3:如果cacheEnabled為true,則建立CachingExecutory,然後在其內部持有上面建立的Executor,cacheEnabled預設為true,則預設建立的Executor為CachingExecutor,並且其內部包裹著SimpleExecutor。 程式碼@4:使用InterceptorChain.pluginAll為executor建立代理物件,即Mybatis的拆件機制,將在該系列文章中詳細介紹。
2、StatementHandler
在學習StatementHandler之前,我們先來回顧一下JDBC相關的知識。JDBC與語句執行的兩大主流物件:java.sql.Statement、java.sql.PrepareStatement物件大家應該不會陌生,該物件的execute方法就是執行SQL語句的入口,通過java.sql.Connection物件建立Statement物件。Mybatis的StatementHandler,是Mybatis建立Statement物件的處理器,即StatementHandler會接管Statement物件的建立。
2.1 StatementHandler類圖
-
StatementHandler 根介面,我們重點關注一下其定義的方法:
- Statement prepare(Connection connection) 建立Statement物件,即該方法會通過Connection物件建立Statement物件。
- void parameterize(Statement statement) 對Statement物件引數化,特別是PreapreStatement物件。
- void batch(Statement statement) 批量執行SQL。
- int update(Statement statement) 更新操作。
- < E> List< E> query(Statement statement, ResultHandler resultHandler) 查詢操作。
- BoundSql getBoundSql() 獲取SQL語句。
- ParameterHandler getParameterHandler() 獲取對應的引數處理器。
-
BaseStatementHandler StatementHandler的抽象實現類,SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler是其子類。 我們來一一看一下其示例變數:
- Configuration configuration Mybatis全域性配置物件。
- ObjectFactory objectFactory 物件工廠。
- TypeHandlerRegistry typeHandlerRegistry 型別註冊器。
- ResultSetHandler resultSetHandler 結果集Handler。
- ParameterHandler parameterHandler 引數處理器Handler。
- Executor executor SQL執行器。
- MappedStatement mappedStatement SQL對映語句(Mapper.xml檔案每一個方法對應一個MappedStatement物件)
- RowBounds rowBounds 行邊界,主要值分頁引數limit、offset。
- BoundSql boundSql 可以通過該物件獲取SQL語句。
-
SimpleStatementHandler 具體的StatementHandler實現器,java.sql.Statement物件建立處理器。
-
PrepareStatementHandler java.sql.PrepareStatement物件的建立處理器。
-
CallableStatementHandler java.sql.CallableStatement物件的建立處理器,可用來執行儲存過程呼叫的Statement。
-
RoutingStatementHandler StatementHandler路由器,我們看一下其構造方法後,就會對該類瞭然於胸。
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) { // @1
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
複製程式碼
原來是會根據MappedStatement物件的statementType建立對應的StatementHandler。
2.2 建立StatementHandler
Configuration#newStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // @1
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); // @2
return statementHandler;
}
複製程式碼
該方法的兩個關鍵點如下: 程式碼@1:建立RoutingStatementHandler物件,在其內部再根據SQL語句的型別,建立對應的StatementHandler物件。 程式碼@2:對StatementHandler引入拆件機制,該部分將在該專題的後續文章中會詳細介紹,這裡暫時跳過。
3、ParameterHandler
引數處理器。同樣我們先來看一下其類圖。
3.1 ParameterHandler類圖
這個比較簡單,就是處理PreparedStatemet介面的引數化處理,也可以順便看一下其呼叫鏈(該部分會在下一篇中詳細介紹)。3.2 建立ParameterHandler
Configuration#newParameterHandler
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); // @1
return parameterHandler;
}
複製程式碼
同樣該介面也支援外掛化機制。
4、ResultSetHandler
處理結果的Handler。我們同樣看一下其類圖。
4.1 ResultSetHandler類圖
處理Jdbc ResultSet的處理器。4.2 ResultSetHandler建立
Configuration#newResultSetHandler
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
複製程式碼
同樣支援外掛化機制,我們也稍微再看一下其呼叫鏈:
可以看出其呼叫的入口為SQL執行時。本文作為下一篇《原始碼分析Mybatis整合ShardingJdbc SQL執行流程》的前置篇,重點介紹Executor、StatementHandler、ParameterHandler、ResultSetHandler的具體職責,以類圖為基礎並詳細介紹其核心方法的作用,然後詳細介紹了這些物件是如何建立,並引出Mybatis拆件機制。
作者介紹:《RocketMQ技術內幕》作者,維護公眾號:中介軟體興趣圈,目前主要發表了原始碼閱讀java集合、JUC(java併發包)、Netty、ElasticJob、Mycat、Dubbo、RocketMQ、mybaits等系列原始碼。