mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回

mybatis源码学习及分析之执行过程分析——返回结果的处理
        上一篇中分析了sql语句的创建和执行过程,使用jdbc时,执行完sql后会返回ResultSet,然后我们会通过getInteger()、getString()等方法拿到数据。而使用Mybatis中我们可以直接将结果转换为POJO对象,下面就来看看mybatis是如何封装ResultSet的。

PreparedStatementHandler.java

  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    //在这里开始结果处理
    return resultSetHandler. handleResultSets(ps);
  }

这里用到了ResultSetHandler。

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第1张图片

DefaultResultSetHandler.java

  public List handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mapdpedStatement.getId());

    final List multipleResults = new ArrayList();

    int resultSetCount = 0;
    //获取ResultSet并包装为ResultSetWrapper 
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }


  private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    //JDBC中的代码,在这里拿到了ResultSet 
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
      // move forward to get the first resultset in case the driver
      // doesn't return the resultset as the first result (HSQLDB 2.1)
      if (stmt.getMoreResults()) {
        rs = stmt.getResultSet();
      } else {
        if (stmt.getUpdateCount() == -1) {
          // no more results. Must be no resultset
          break;
        }
      }
    }
    //将ResultSet包装为ResultSetWrapper
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  } 
  

当前调用栈信息: 

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第2张图片

当ResultSet不为空时,也就是查到了结果,通过rs和Configuration实例化了ResultSetWrapper。

public class ResultSetWrapper {

  private final ResultSet resultSet;
  private final TypeHandlerRegistry typeHandlerRegistry;
  private final List columnNames = new ArrayList();
  private final List classNames = new ArrayList();
  private final List jdbcTypes = new ArrayList();
  private final Map, TypeHandler>> typeHandlerMap = new HashMap, TypeHandler>>();
  private Map> mappedColumnNamesMap = new HashMap>();
  private Map> unMappedColumnNamesMap = new HashMap>();

  public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
    super();
    //从configuration中拿到了typeHandlerRegistry 
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.resultSet = rs;

    //拿到了列信息
    final int columnCount = metaData.getColumnCount();
    //将每一列的名称、jdbc类型、java类型分别保存在三个ArrayList中。
    for (int i = 1; i <= columnCount; i++) { 
      columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
      classNames.add(metaData.getColumnClassName(i));
    }
  }
  。。。
 }

当前调用栈如下图:

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第3张图片

返回的ResultSetWrapper信息如图: 

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第4张图片

到这里,我们的调用栈就返回到了DefaultResultHandler#handleResultSets(Statement stmt)

接下来通过mappedStatement拿到了xml中配置的ResultMap。 

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第5张图片

可以看到ResultMap是我们将jdbc类型数据映射为POJO对象的重要手段。

validateResultMapsCount(rsw, resultMapCount);

对ResultMap进行校验,当查询返回的ResultMap数量小于1时,说明没有找到对应的ResultType或者ResultMap可以将结果映射出来,在这里就会抛出ExecutorException异常。

接下来重要的操作就是handleResultSet(rsw, resultMap, multipleResults, null);这里开始对结果集进行封装。
 

DefaultResultSetHandler.java

  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 handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext resultContext = new DefaultResultContext();
    skipRows(rsw.getResultSet(), rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      //调用getRowValue
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //创建了User
    Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        //拿到列信息
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      resultObject = foundValues ? resultObject : null;
      return resultObject;
    }
    return resultObject;
  }

//调用User的setter方法为User实例设置信息
  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    final List mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    final List propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
      String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      if (propertyMapping.getNestedResultMapId() != null) {
        // the user added a column attribute to a nested result map, ignore it
        column = null;
      }
      if (propertyMapping.isCompositeResult()
          || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
          || propertyMapping.getResultSet() != null) {
          //getPropertyMappingValue在这里对了数据转换
        Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
        // issue #541 make property optional
        final String property = propertyMapping.getProperty();
        if (property == null) {
          continue;
        } else if (value == DEFERED) {
          foundValues = true;
          continue;
        }
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          //在这里使用了setter方法设置值
          metaObject.setValue(property, value);
        }
      }
    }
    return foundValues;
  } 
  

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第6张图片

可以看到调用了User的setName。

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第7张图片


  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 {
       //typeHandler
      final TypeHandler typeHandler = propertyMapping.getTypeHandler();
      //数据库表的列名
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      //得到数据库中信息
      return typeHandler.getResult(rs, column);
    }
  }

当所有的值都设置完成后,已经得到了我们需要的POJO类信息,调用栈开始出栈操作,方法return。 

mybatis源码学习之执行过程分析——sql执行后ResultSet的处理及结果返回_第8张图片

至此,结果封装完成,所有调用栈开始出栈操作,最后返回我们需要的User。

 

你可能感兴趣的:(mybatis)