天天看點

Mybatis源碼解析十二之ParameterHandler

介紹

ParameterHandler是在SatementHandler執行prepared比如預編譯SQL後,設定參數時使用的類

接口

ParameterHandler也隻是一個接口

public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps)
      throws SQLException;

}
           

說明:

- 隻有兩個方法:擷取參數和設定參數。

  • 它隻有一個實作類DefaultParameterHandler.java

ParameterHandler的建立。

通過源碼調用分析,可以看到ParameterHandler是在StatementHandler對象建立時,一起建立的.

具體代碼如下:

BaseStatementHandler.java

 protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    ...
    ## ParemeterHandler建立入口
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    ## ResultHandler建立入口
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

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

   XMLLanguageDriver
  @Override
  public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ## 這裡建立 DefaultParameterHandler
    return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
  }
           

建立時 傳入三個對象:執行SQL對應的配置資訊MappedStatement、參數對象Object,SQL的BoundSql。

注:一個BoundSql對象,代表了一次sql語句的實際執行,而SqlSource對象的責任,就是根據傳入的參數對象,動态計算出這個BoundSql,也就是說Mapper檔案中的節點的計算,是由SqlSource對象完成的。SqlSource最常用的實作類是DynamicSqlSource

setParement

設定參數

@Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    ## 1.擷取所有參數,ParameterMapping是java類型和jdbc類型的對應關系   
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = ; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          ## 擷取參數名
          String propertyName = parameterMapping.getProperty();
          ## 根據參數名擷取參數值
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          //擷取參數值對應的jdbc類型  
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            typeHandler.setParameter(ps, i + , 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);
          }
        }
      }
    }
  }
           

parameterObject 參數,可以是MAP,一個實體對象,或者基本資料類型。

上面大緻流程是,根據參數清單,使用BaseTypeHandler來設定參數。BaseTypeHandler其底層調用的是java的PreparedStatement.setXXX 方法來設定參數。

調用時機說明:

setParameter方法是在Executor進行調用的。

以SimpleExecutor為例

@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
  ## 擷取連接配接、預編譯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;
  }
           

參考

  • Mybatis 之 ParameterHandler
  • MappedStatement,SqlSource,BoundSql

繼續閱讀