>舒適提示:本篇是源碼分析Mybatis ShardingJdbc SQL語句執行的前置篇。java
sql執行器,其對應的類全路徑:org.apache.ibatis.executor.Executor。sql
Executorapache
執行器根據接口,定義update(更新或插入)、query(查詢)、commit(提交事務)、rollback(回滾事務)。接下來簡單介紹幾個重要方法:設計模式
int update(MappedStatement ms, Object parameter) throws SQLException 更新或插入方法,其參數含義以下:緩存
1)MappedStatement ms:SQL映射語句(Mapper.xml文件每個方法對應一個MappedStatement對象)併發
2)Object parameter:參數,一般是List集合。app
< E> List< E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)源碼分析
查詢方法,其參數含義以下:學習
1)RowBounds:行邊界,主要值分頁參數limit、offset。this
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對象。
在Mybatis中,Executor的建立由Configuration對象來建立,具體的代碼以下:
public Executor newExecutor(Transaction transaction) { return newExecutor(transaction, defaultExecutorType); // [@1](https://my.oschina.net/u/1198) } 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](https://my.oschina.net/u/2648711) 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的拆件機制,將在該系列文章中詳細介紹。
在學習StatementHandler以前,咱們先來回顧一下JDBC相關的知識。JDBC與語句執行的兩大主流對象:java.sql.Statement、java.sql.PrepareStatement對象你們應該不會陌生,該對象的execute方法就是執行SQL語句的入口,經過java.sql.Connection對象建立Statement對象。Mybatis的StatementHandler,是Mybatis建立Statement對象的處理器,即StatementHandler會接管Statement對象的建立。
StatementHandler 根接口,咱們重點關注一下其定義的方法:
BaseStatementHandler StatementHandler的抽象實現類,SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler是其子類。 咱們來一一看一下其示例變量:
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。
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引入拆件機制,該部分將在該專題的後續文章中會詳細介紹,這裏暫時跳過。
參數處理器。一樣咱們先來看一下其類圖。
這個比較簡單,就是處理PreparedStatemet接口的參數化處理,也能夠順便看一下其調用鏈(該部分會在下一篇中詳細介紹)。
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; }
一樣該接口也支持插件化機制。
處理結果的Handler。咱們一樣看一下其類圖。
處理Jdbc ResultSet的處理器。
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技術內幕》做者,RocketMQ 社區佈道師,公衆號:中間件興趣圈 維護者,目前已陸續發表源碼分析Java集合、Java 併發包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源碼專欄。