舒適提示:本篇是源碼分析Mybatis ShardingJdbc SQL語句執行的前置篇,重點闡述Mybatis執行SQL語句的4大核心組件。
源碼分析Mybatis系列目錄:
一、源碼分析Mybatis MapperProxy初始化【圖文並茂】
二、源碼分析Mybatis MappedStatement的建立流程java
sql執行器,其對應的類全路徑:org.apache.ibatis.executor.Executor。sql
舒適提示:若是圖片不清晰,能夠瀏覽該網址:http://www.javashuo.com/article/p-uiuwcfeb-hb.htmlapache
Executor
執行器根據接口,定義update(更新或插入)、query(查詢)、commit(提交事務)、rollback(回滾事務)。接下來簡單介紹幾個重要方法:設計模式
CachingExecutor
支持結果緩存的SQL執行器,注意其設計模式的應用,該類中,會持有Executor的一個委託對象,CachingExecutor關注與緩存特定的邏輯,其最終的SQL執行由其委託對象來實現,即其內部的委託對象爲BaseExecutor的實現類。緩存
BaseExecutor
Executor的基礎實現類,該類爲抽象類,關於查詢、更新具體的實現由其子類來實現,下面4個都是其子類。微信
SimpleExecutor
簡單的Executor執行器。app
BatchExecutor
支持批量執行的Executor執行器。運維
ClosedExecutor
表示一個已關閉的Executor。ide
在Mybatis中,Executor的建立由Configuration對象來建立,具體的代碼以下:源碼分析
1public Executor newExecutor(Transaction transaction) { 2 return newExecutor(transaction, defaultExecutorType); // @1 3} 4 5 6public Executor newExecutor(Transaction transaction, ExecutorType executorType) { 7 executorType = executorType == null ? defaultExecutorType : executorType; 8 executorType = executorType == null ? ExecutorType.SIMPLE : executorType; 9 Executor executor; 10 if (ExecutorType.BATCH == executorType) { // @2 11 executor = new BatchExecutor(this, transaction); 12 } else if (ExecutorType.REUSE == executorType) { 13 executor = new ReuseExecutor(this, transaction); 14 } else { 15 executor = new SimpleExecutor(this, transaction); 16 } 17 if (cacheEnabled) { // @3 18 executor = new CachingExecutor(executor); 19 } 20 executor = (Executor) interceptorChain.pluginAll(executor); // @4 21 return executor; 22}
從上面的代碼能夠看出,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的拆件機制,將在該系列文章中詳細介紹。
在學習StatementHandler以前,咱們先來回顧一下JDBC相關的知識。JDBC與語句執行的兩大主流對象:java.sql.Statement、java.sql.PrepareStatement對象你們應該不會陌生,該對象的execute方法就是執行SQL語句的入口,經過java.sql.Connection對象建立Statement對象。Mybatis的StatementHandler,是Mybatis建立Statement對象的處理器,即StatementHandler會接管Statement對象的建立。
根接口,咱們重點關注一下其定義的方法:
BaseStatementHandler
StatementHandler的抽象實現類。咱們來一一看一下其示例變量:
SimpleStatementHandler
具體的StatementHandler實現器,java.sql.Statement對象建立處理器。
PrepareStatementHandler
java.sql.PrepareStatement對象的建立處理器。
CallableStatementHandler
java.sql.CallableStatement對象的建立處理器,可用來執行存儲過程調用的Statement。
RoutingStatementHandler
StatementHandler路由器,咱們看一下其構造方法後,就會對該類瞭然於胸。
1public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 2 3 switch (ms.getStatementType()) { // @1 4 case STATEMENT: 5 delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 6 break; 7 case PREPARED: 8 delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 9 break; 10 case CALLABLE: 11 delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 12 break; 13 default: 14 throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); 15 } 16 17}
原來是會根據MappedStatement對象的statementType建立對應的StatementHandler。
1public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 2 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // @1 3 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); // @2 4 return statementHandler; 5}
該方法的兩個關鍵點以下:
代碼@1:建立RoutingStatementHandler對象,在其內部再根據SQL語句的類型,建立對應的StatementHandler對象。
代碼@2:對StatementHandler引入拆件機制,該部分將在該專題的後續文章中會詳細介紹,這裏暫時跳過。
參數處理器。一樣咱們先來看一下其類圖。
這個比較簡單,就是處理PreparedStatemet接口的參數化處理,也能夠順便看一下其調用鏈(該部分會在下一篇中詳細介紹)。
Configuration#newParameterHandler
1public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { 2 ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); 3 parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); // @1 4 return parameterHandler; 5}
一樣該接口也支持插件化機制。
處理結果的Handler。咱們一樣看一下其類圖。
處理Jdbc ResultSet的處理器。
1public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, 2 ResultHandler resultHandler, BoundSql boundSql) { 3 ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); 4 resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); 5 return resultSetHandler; 6}
一樣支持插件化機制,咱們也稍微再看一下其調用鏈:
能夠看出其調用的入口爲SQL執行時。
本文做爲下一篇《源碼分析Mybatis整合ShardingJdbc SQL執行流程》的前置篇,詳細介紹Executor、StatementHandler、ParameterHandler、ResultSetHandler的具體職責,以類圖爲基礎詳細介紹其核心方法的做用,而後講述這些對象如何建立並引出Mybatis拆件機制。並引出Mybatis拆件機制。
更多文章請關注微信公衆號:
一波廣告來襲,做者新書《RocketMQ技術內幕》已出版上市:
《RocketMQ技術內幕》已出版上市,目前可在主流購物平臺(京東、天貓等)購買,本書從源碼角度深度分析了RocketMQ NameServer、消息發送、消息存儲、消息消費、消息過濾、主從同步HA、事務消息;在實戰篇重點介紹了RocketMQ運維管理界面與當前支持的39個運維命令;並在附錄部分羅列了RocketMQ幾乎全部的配置參數。本書獲得了RocketMQ創始人、阿里巴巴Messaging開源技術負責人、Linux OpenMessaging 主席的高度承認並做序推薦。目前是國內第一本成體系剖析RocketMQ的書籍。