mybatis之结果映射源码分析

5 篇文章 0 订阅
3 篇文章 0 订阅

1、DefaultResultSetHandler#handleResultSets

 public List<Object> handleResultSets(Statement stmt) throws SQLException {
	// 最终返回的结果集合
    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
   // 疑问:一个MapperStatement id可以对应多个ResultMap?
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }
    ...
    return collapseSingleResultList(multipleResults);
}
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping 	
	parentMapping) throws SQLException {
    	DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
       	handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        multipleResults.add(defaultResultHandler.getResultList());
}
  • 结果集合multipleResults最终是通过DefaultResultHandler#list属性获取到的。
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds 
	rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {// 默认执行分支 resultHandler:DefaultResultHandler
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
}

处理ReturnType集合

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> 
	resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();// 获取到结果集
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
}
  • rowValue代表完成初始化的返回值。
  • while循环表示循环处理返回类型为list集合类型的结果集。

storeObject

private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
  if (parentMapping != null) {
    linkToParents(rs, parentMapping, rowValue);
  } else {
    callResultHandler(resultHandler, resultContext, rowValue);
  }
}

private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
  resultContext.nextResultObject(rowValue);
  ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
  • 得到最终结果时由DefaultResultContext#nextResultObject持有。
  • 最终DefaultResultHandler通过DefaultResultContext获取到结果值赋值到DefaultResultHandler属性list。

初始化ReturnType

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
  final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
  if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    boolean foundValues = this.useConstructorMappings;
    if (shouldApplyAutomaticMappings(resultMap, false)) {
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
    }
    foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
  }
  return rowValue;
}
  • createResultObject得到当前SQL返回值类型ReturnType。
  • 此处主要处理非TypeHandler对应的基本数据类型,也即处理返回值值为类引用类型的实体类。
  • applyAutomaticMappings优先处理ReturnType中无法自动映射字段的初始化。
  • applyPropertyMappings再次处理剩下字段的初始化。
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  // UnMappedColumnAutoMapping:表示列名和实体类字段名不一致导致无法自动映射。
  List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  boolean foundValues = false;
  if (!autoMapping.isEmpty()) {
    for (UnMappedColumnAutoMapping mapping : autoMapping) {
      // 从ResultSet集中获取对应结果值
      final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
      if (value != null) {
        foundValues = true;
      }
      if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
      	//metaObject对应的是返回值类型。最终将无法自动映射的字段赋值
        metaObject.setValue(mapping.property, value);
      }
    }
  }
  return foundValues;
}
  • UnMappedColumnAutoMapping目的是处理跟列名不一致的字段。
  • 从ResultSet集中获取当前字段的取值。
  • 将value赋值给当前实体类metaObject的对应的字段。
 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);// 处理实体类的返回值类型
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }
  • TypeHandler:主要处理ReturnType为基本数据类型的返回值。
  • objectFactory:主要处理ReturnType为引用类型的返回值。
private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
  final Class<?> resultType = resultMap.getType();
  final String columnName;
  if (!resultMap.getResultMappings().isEmpty()) {
    final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
    final ResultMapping mapping = resultMappingList.get(0);
    columnName = prependPrefix(mapping.getColumn(), columnPrefix);
  } else {
    columnName = rsw.getColumnNames().get(0);// count(0)
  }
  final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
  return typeHandler.getResult(rsw.getResultSet(), columnName);
}
  • 针对获取分页总数时,其属性ResultMapping被初始化为空。
  • 针对获取分页总数时,其ResultSet集中其对应的列名默认为count(0)。除非自己设置了别名。
  • 针对获取分页总数时,最终通过列名从ResultSet集中获取对应的结果值。

PageHelper

PageHelper插件处理分页总数时,需要重新初始化MappedStatement。

public static MappedStatement newCountMappedStatement(MappedStatement ms, String newMsId) {
    MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), newMsId, ms.getSqlSource(), ms.getSqlCommandType());
    builder.resource(ms.getResource());
    builder.fetchSize(ms.getFetchSize());
    builder.statementType(ms.getStatementType());
    builder.keyGenerator(ms.getKeyGenerator());
    if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
        StringBuilder keyProperties = new StringBuilder();
        for (String keyProperty : ms.getKeyProperties()) {
            keyProperties.append(keyProperty).append(",");
        }
        keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
        builder.keyProperty(keyProperties.toString());
    }
    builder.timeout(ms.getTimeout());
    builder.parameterMap(ms.getParameterMap());
    //count查询返回值int
    List<ResultMap> resultMaps = new ArrayList<ResultMap>();
    // 初始化ResultMap时,其属性resultMappings默认为空的EMPTY_RESULTMAPPING
    ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Long.class, EMPTY_RESULTMAPPING).build();
    resultMaps.add(resultMap);
    builder.resultMaps(resultMaps);
    builder.resultSetType(ms.getResultSetType());
    builder.cache(ms.getCache());
    builder.flushCacheRequired(ms.isFlushCacheRequired());
    builder.useCache(ms.isUseCache());

    return builder.build();
}

DefaultResultHandler

public class DefaultResultHandler implements ResultHandler<Object> {

  private final List<Object> list;

  public DefaultResultHandler() {
    list = new ArrayList<>();
  }
  @SuppressWarnings("unchecked")
  public DefaultResultHandler(ObjectFactory objectFactory) {
    list = objectFactory.create(List.class);
  }

  @Override
  public void handleResult(ResultContext<?> context) {
    list.add(context.getResultObject());
  }

  public List<Object> getResultList() {
    return list;
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis是一个Java持久层框架,提供了灵活的SQL映射和便捷的数据库访问。Mapper接口是MyBatis中定义SQL映射的方式之一。下面是MyBatis Mapper源码分析的一般步骤: 1. 首先,需要了解Mapper接口和XML映射文件之间的对应关系。在XML映射文件中定义了SQL语句和结果映射规则,而Mapper接口则提供了对应的方法。 2. 接下来,可以分析Mapper接口的实现类。MyBatis会动态生成Mapper接口的实现类,这些实现类会根据XML映射文件中定义的SQL语句进行具体的数据库操作。 3. 在实现类中,可以找到具体的数据库操作方法。这些方法会通过SqlSession对象执行对应的SQL语句,并返回结果。 4. 在执行SQL语句之前,MyBatis会进行参数解析和类型转换等操作。可以分析这部分代码,了解参数处理的过程。 5. SQL语句的执行过程中,还涉及到一些与数据库连接相关的操作,比如连接的获取和释放。可以查看这部分代码,了解连接管理的实现方式。 6. 最后,可以分析SQL语句的执行结果处理过程。MyBatis会根据XML映射文件中定义的结果映射规则,将查询结果转换成相应的Java对象。 需要注意的是,MyBatis源码比较庞大复杂,以上只是对Mapper源码分析的一般步骤。具体的分析过程可能会因版本和具体使用情况而有所不同。建议先阅读MyBatis的官方文档和相关资料,对其基本原理有所了解,再进行源码分析

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值