mybatis类型处理器typeHandlers详解

系列

  • MyBatis拦截器原理介绍
  • Mybatis拦截器改写请求参数和结果
  • Mybatis 插件兼容动态SQL
  • mybatis 参数解析流程附相关案例
  • 详述mybatis执行流程

开篇

  • MyBatis的 类型处理器 在设置预处理语句中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型

  • 本篇文章基于mybatis-3.5.7分支进行分析,梳理MyBatis类型处理器在源码层面的实现,包含类型处理解析、请求集处理、结果集处理三个方向。


类型处理器解析

  private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {

    private List parameterMappings = new ArrayList<>();
    private Class parameterType;
    private MetaObject metaParameters;

    private ParameterMapping buildParameterMapping(String content) {
      Map propertiesMap = parseParameterMapping(content);

      // 省略相关代码

      ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
      Class javaType = propertyType;
      String typeHandlerAlias = null;
      for (Map.Entry entry : propertiesMap.entrySet()) {
        String name = entry.getKey();
        String value = entry.getValue();
        if ("javaType".equals(name)) {
          javaType = resolveClass(value);
          builder.javaType(javaType);
        } else if ("jdbcType".equals(name)) {
          builder.jdbcType(resolveJdbcType(value));
        } else if ("mode".equals(name)) {
          builder.mode(resolveParameterMode(value));
        } else if ("numericScale".equals(name)) {
          builder.numericScale(Integer.valueOf(value));
        } else if ("resultMap".equals(name)) {
          builder.resultMapId(value);
        // 解析对应的typeHandler参数
        } else if ("typeHandler".equals(name)) {
          typeHandlerAlias = value;
        } else if ("jdbcTypeName".equals(name)) {
          builder.jdbcTypeName(value);
        } else if ("property".equals(name)) {
          // Do Nothing
        } else if ("expression".equals(name)) {
          // 省略相关代码
        } else {
          // 省略相关代码
        }
      }
      // 设置对应的typeHandlerAlias参数
      if (typeHandlerAlias != null) {
        builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
      }
      // 构建对应的ParameterMapping对象
      return builder.build();
    }
  }
  • 在参数解析的方法ParameterMappingTokenHandler中通过resolveTypeHandler实现类型处理器的解析。
  • ParameterMappingTokenHandler负责生成ParameterMapping对象,里面包含typeHandler对象。


请求集处理

public class DefaultParameterHandler implements ParameterHandler {

  private final TypeHandlerRegistry typeHandlerRegistry;
  private final MappedStatement mappedStatement;
  private final Object parameterObject;
  private final BoundSql boundSql;
  private final Configuration configuration;

  public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    this.mappedStatement = mappedStatement;
    this.configuration = mappedStatement.getConfiguration();
    this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
    this.parameterObject = parameterObject;
    this.boundSql = boundSql;
  }

  @Override
  public Object getParameterObject() {
    return parameterObject;
  }

  @Override
  public void setParameters(PreparedStatement ps) {

    List parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      // 遍历所有的参数映射
      for (int i = 0; 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);
          }

          // 获取参数类型处理器TypeHandler对象
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }

          try {
            // 通过类型处理器进行参数解析
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
          }
        }
      }
    }
  }
}
  • DefaultParameterHandler#setParameters方法会遍历parameterMappings并调用typeHandler.setParameter的处理参数并进行设置。


结果集处理

public interface ResultSetHandler {
   List handleResultSets(Statement stmt) throws SQLException;
   Cursor handleCursorResultSets(Statement stmt) throws SQLException;
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}


public interface TypeHandler {
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  T getResult(ResultSet rs, String columnName) throws SQLException;
  T getResult(ResultSet rs, int columnIndex) throws SQLException;
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

public abstract class BaseTypeHandler extends TypeReference implements TypeHandler {

  protected Configuration configuration;
}
  • 结果集处理的接口ResultSetHandler包含上述的方法,针对结果处理的方法内会执行类型处理器TypeHandler。
  • 类型处理器TypeHandler开放的接口如上述定义,自定义类型处理器需要实现上述功能。
  • 考虑实现TypeHandler的接口的复杂度较高,可以通过继承BaseTypeHandler来简化接口操作。
public class DefaultResultSetHandler implements ResultSetHandler {

  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, 
                               List multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          // 处理每行的结果值
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }


  private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, 
          ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {

    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }


  private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, 
                          ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {

    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
      return DEFERED;
    } else {
      final TypeHandler typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      // 通过typeHandler进行处理
      return typeHandler.getResult(rs, column);
    }
  }
}

  • 结果集的处理核心在DefaultResultSetHandler当中,在内部逻辑中会调用到typeHandler。
  • 结果集处理的例子之一是通过typeHandler.getResult来处理结果。


参考

  • 类型处理器(typeHandlers)
  • MyBatis自定义类型处理器 TypeHandler

你可能感兴趣的:(mybatis类型处理器typeHandlers详解)