1. 程式人生 > >MyBatis 核心配置綜述之 ParameterHandler

MyBatis 核心配置綜述之 ParameterHandler

目錄

    • ParameterHandler 簡介
    • ParameterHandler 建立
    • ParameterHandler 中的引數從何而來
    • ParameterHandler 解析

MyBatis 四大核心元件我們已經瞭解到了兩種,一個是 Executor ,它是MyBatis 解析SQL請求首先會經過的第一道關卡,它的主要作用在於建立快取,管理 StatementHandler 的呼叫,為 StatementHandler 提供 Configuration 環境等。StatementHandler 元件最主要的作用在於建立 Statement 物件與資料庫進行交流,還會使用 ParameterHandler 進行引數配置,使用 ResultSetHandler 把查詢結果與實體類進行繫結。那麼本篇就來了解一下第三個元件 ParameterHandler。

ParameterHandler 簡介

ParameterHandler 相比於其他的元件就簡單很多了,ParameterHandler 譯為引數處理器,負責為 PreparedStatement 的 sql 語句引數動態賦值,這個介面很簡單隻有兩個方法

/**
 * A parameter handler sets the parameters of the {@code PreparedStatement}
 * 引數處理器為 PreparedStatement 設定引數
 */
public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps)
      throws SQLException;

}

ParameterHandler 只有一個實現類 DefaultParameterHandler , 它實現了這兩個方法。

  • getParameterObject: 用於讀取引數
  • setParameters: 用於對 PreparedStatement 的引數賦值

ParameterHandler 建立

引數處理器物件是在建立 StatementHandler 物件的同時被建立的,由 Configuration 物件負責建立

BaseStatementHandler.java

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  this.configuration = mappedStatement.getConfiguration();
  this.executor = executor;
  this.mappedStatement = mappedStatement;
  this.rowBounds = rowBounds;

  this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  this.objectFactory = configuration.getObjectFactory();

  if (boundSql == null) { // issue #435, get the key before calculating the statement
    generateKeys(parameterObject);
    boundSql = mappedStatement.getBoundSql(parameterObject);
  }

  this.boundSql = boundSql;

  // 建立引數處理器
  this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
  // 建立結果對映器
  this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

在建立 ParameterHandler 時,需要傳入SQL的mappedStatement 物件,讀取的引數和SQL語句

注意:一個 BoundSql 物件,就代表了一次sql語句的實際執行,而 SqlSource 物件的責任,就是根據傳入的引數物件,動態計算這個 BoundSql, 也就是 Mapper 檔案中節點的計算,是由 SqlSource 完成的,SqlSource 最常用的實現類是 DynamicSqlSource

Configuration.java

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  // 建立ParameterHandler
  ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
  parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  return parameterHandler;
}

上面是 Configuration 建立 ParameterHandler 的過程,它實際上是交由 LanguageDriver 來建立具體的引數處理器,LanguageDriver 預設的實現類是 XMLLanguageDriver,由它呼叫 DefaultParameterHandler 中的構造方法完成 ParameterHandler 的建立工作

public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}

public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  this.mappedStatement = mappedStatement;
  this.configuration = mappedStatement.getConfiguration();
  // 獲取 TypeHandlerRegistry 註冊
  this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
  this.parameterObject = parameterObject;
  this.boundSql = boundSql;
}

上面的流程是建立 ParameterHandler 的過程,建立完成之後,該進行具體的解析工作,那麼 ParameterHandler 如何解析SQL中的引數呢?SQL中的引數從哪裡來的?

ParameterHandler 中的引數從何而來

你可能知道 Parameter 中的引數是怎麼來的,無非就是從 Mapper 配置檔案中對映過去的啊,就比如如下例子

引數肯定就是圖中標紅的 1 ,然後再傳到XML對應的 SQL 語句中,用 #{} 或者 ${} 來進行賦值啊,

嗯,你講的沒錯,可是你知道這個引數是如何對映過來的嗎?或者說你知道 Parameter 的解析過程嗎?或許你不是很清晰了,我們下面就來探討一下 ParameterHandler 對引數的解析,這其中涉及到 MyBatis 中的動態代理模式

在MyBatis 中,當 deptDao.findByDeptNo(1) 將要執行的時候,會被 JVM 進行攔截,交給 MyBatis 中的代理實現類 MapperProxy 的 invoke 方法中,這也是執行 SQL 語句的主流程。

然後交給 Executor 、StatementHandler進行對應的引數解析和執行,因為是帶引數的 SQL 語句,最終會建立 PreparedStatement 物件並建立引數解析器進行引數解析

SimpleExecutor.java

handler.parameterize(stmt) 最終會呼叫到 DefaultParameterHandler 中的 setParameters 方法,我在原始碼上做了註釋,為了方便拷貝,我沒有采用截圖的形式

public void setParameters(PreparedStatement ps) {
  ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  // parameterMappings 就是對 #{} 或者 ${} 裡面引數的封裝
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings != null) {
    // 如果是引數化的SQL,便需要迴圈取出並設定引數的值
    for (int i = 0; i < parameterMappings.size(); i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      // 如果引數型別不是 OUT ,這個型別與 CallableStatementHandler 有關
      // 因為儲存過程不存在輸出引數,所以引數不是輸出引數的時候,就需要設定。
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        // 得到#{}  中的屬性名
        String propertyName = parameterMapping.getProperty();
        // 如果 propertyName 是 Map 中的key
        if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
          // 通過key 來得到 additionalParameter 中的value值
          value = boundSql.getAdditionalParameter(propertyName);
        }
        // 如果不是 additionalParameters 中的key,而且傳入引數是 null, 則value 就是null
        else if (parameterObject == null) {
          value = null;
        }
        // 如果 typeHandlerRegistry 中已經註冊了這個引數的 Class物件,即它是Primitive 或者是String 的話
        else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          // 否則就是 Map
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        // 在通過SqlSource 的parse 方法得到parameterMappings 的具體實現中,我們會得到parameterMappings的typeHandler
        TypeHandler typeHandler = parameterMapping.getTypeHandler();
        // 獲取typeHandler 的jdbc type
        JdbcType jdbcType = parameterMapping.getJdbcType();
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        try {
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        } catch (SQLException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        }
      }
    }
  }
}

ParameterHandler 解析

我們在 MyBatis 核心配置綜述之 StatementHandler 一文中瞭解到 Executor 管理的是 StatementHandler 物件的建立以及引數賦值,那麼我們的主要入口還是 Executor 執行器

下面用一個流程圖表示一下 ParameterHandler 的解析過程,以簡單執行器為例

像是 doQuery,doUpdate,doQueryCursor等方法都會先呼叫到

// 生成 preparedStatement 並呼叫 prepare 方法,併為引數賦值
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  Connection connection = getConnection(statementLog);
  stmt = handler.prepare(connection, transaction.getTimeout());
  handler.parameterize(stmt);
  return stmt;
}

然後在生成 preparedStatement 呼叫DefaultParameterHandler進行引數賦值。

公眾號提供 優質Java資料 以及CSDN免費下載 許可權,歡迎你關注我

相關推薦

MyBatis 核心配置綜述 ParameterHandler

目錄 ParameterHandler 簡介 ParameterHandler 建立 ParameterHandler 中的引數從何而來 ParameterHandler 解析

MyBatis 核心配置綜述Executor

目錄 MyBatis四大元件之 Executor執行器 Executor的繼承結構 Executor建立過程以及原始碼分析 Executor介面的主要方法 Executor

MyBatis 核心配置綜述StatementHandler

目錄 MyBatis 核心配置綜述之StatementHandler MyBatis 四大元件之StatementHandler StatementHandler 的基本構成 StatementHandler

MyBatis 核心配置綜述 ResultSetHandler

目錄 ResultSetHandler 簡介 ResultSetHandler 建立 ResultSetHandler 處理結果對映 DefaultResultSetHandler 原始碼解

(手寫)mybatis 核心配置文件和接口不在同一包下的解決方案

內置 中間 configure idea pan 數據源配置 uil 基礎 主目錄 smart-sh-mybatis項目app.xml文件中此處配置為: 1 <!-- 從整合包裏找,org.mybatis:mybatis-spring:1.2.4 -->

Mybatis核心配置檔案SqlMapConfig.xml

配置內容:   SqlMapConfig.xml中配置的內容和順序如下: 1.properties(屬性) 2.settings(全域性配置引數) 3.typeAliases(類型別名) 4.typeHandlers(型別處理器) 5.objectFactory(物件工廠) 6.pl

MyBatis學習總結(二)——MyBatis核心配置檔案與輸入輸出對映

在上一章中我們學習了《MyBatis學習總結(一)——ORM概要與MyBatis快速起步》,這一章主要是介紹MyBatis核心配置檔案、使用介面+XML實現完整資料訪問、輸入引數對映與輸出結果對映等內容。 一、MyBatis配置檔案概要 MyBatis核心配置檔案在初始化時會被引用,在配置檔案中定義了一些

mybatis核心配置檔案詳解

1.屬性(properties) <properties resource="db.properties">         <property name="driver" val

MyBatis核心配置檔案

mybatis核心配置檔案建立步驟: 1)核心配置檔案配置 2)pojo模型建立 3)對映檔案配置 4)獲取SqlSessionFactory 5)獲取SqlSession 6)CRUD操作 7)事務操作 8)關閉SqlSession mybatis的

Mybatis基礎:Mybatis對映配置檔案,Mybatis核心配置檔案,Mybatis傳統方式開發

知識點梳理 詳細講義 一.Mybatis快速入門 1.1 框架介紹 框架是一款半成品軟體,我們可以基於這個半成品軟體繼續開發,來完成我們個性化的需求! 框架:大工具,我們利用工具,可以快速開發專案 (mybatis也是一個jar包,不過提供的功能更加多) jar包:小工具 如圖: &n

mybatis核心配置properties

5.1、建立jdbc.properties一般在實際的專案中。資料庫的連線資訊。會存放在一個jdbc.properties的屬性配置檔案中 username=root password=root driverClass=com.mysql.jdbc.Driver

hibernate框架學習核心配置文件

encoding driver user pool prope jdbc nat false form hibernate.cfg.xml <?xml version=‘1.0‘ encoding=‘utf-8‘?> <!DOCTYPE hibernat

Mybatis 三劍客Mybatis-generator配置

Mybatis-generator 的作用:根據資料庫自動生成 pojo、dao 和對應的 xml 檔案,其中: pojo :放置和資料庫欄位一一對應的物件; dao :介面,供 service 呼叫; xml :dao 層介面的實現; pom 配置 在 &l

MyBatis基本要素---核心配置檔案

今天就簡單的敘述下MyBatis的核心配置檔案吧~~      configuration  配置      properties  可以配置在java屬性配置檔案中      set

Mybatis學習總結一MyBatis配置檔案中的配置及其優化

Mybatis介紹        MyBatis是一個支援普通SQL查詢,儲存過程和高階對映的優秀持久層框架。MyBatis消除了幾乎所有的JDBC程式碼和引數的手工設定以及對結果集的檢索封裝。MyBatis可以使用簡單的XML或註解用於配置和原始對映,將

mybatis四大介面 ParameterHandler

1.  繼承結構   只有一個預設的實現類    2. ParameterHandler   獲取引數物件;   設定引數; public interface ParameterHandler { Object getParameterObject();

Mybatismapper配置檔案方法標籤的引數獲取

Mybatis框架中,Mapper檔案引數獲取一般有以下幾種: 1、引數個數為1個(string或者int)   dao層方法為以下兩種: /** * 單個int型 */ public List<UserComment&g

mybatis 解析配置檔案(一)XML的DOM解析方式

簡介 在之前的文章《mybatis 初步使用(IDEA的Maven專案, 超詳細)》中, 講解了mybatis的初步使用, 並總結了以下mybatis的執行流程: 通過 Resources 工具類讀取 mybatis-config.xml, 存入 Reader; SqlSessionFactoryBuil

dubbo系列spring boot核心配置讀取(三)

版本說明 springboot starter : 0.1.1 dubbo版本: 2.6.2 自動配置類 @Configuration @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled",

MyBatis(3)MyBatis全域性配置檔案

全域性配置檔案(如SqlMapConfig.xml) configuration配置 properties屬性 setting設定 typeAliases型別命名 typeHandlers型別處理器 objectFactory物件工廠 plugins外掛 en