Mybatis執行SQL的4大基礎組件詳解(圖文並茂)

一、Executor

sql執行器,其對應的類全路徑:org.apache.ibatis.executor.Executor。java

1.1 Executor類圖

在這裏插入圖片描述

  • Executor 執行器根據接口,定義update(更新或插入)、query(查詢)、commit(提交事務)、rollback(回滾事務)。接下來簡單介紹幾個重要方法:sql

    • 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的實現類。apache

  • BaseExecutor Executor的基礎實現類,該類爲抽象類,關於查詢、更新具體的實現由其子類來實現,下面4個都是其子類。設計模式

  • SimpleExecutor 簡單的Executor執行器。緩存

  • BatchExecutor 支持批量執行的Executor執行器。併發

  • ClosedExecutor 表示一個已關閉的Executor。app

  • 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的拆件機制,將在該系列文章中詳細介紹。this

二、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引入拆件機制,該部分將在該專題的後續文章中會詳細介紹,這裏暫時跳過。

三、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;
}
複製代碼

一樣該接口也支持插件化機制。

四、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等系列源碼。

在這裏插入圖片描述
相關文章
相關標籤/搜索