MyBatis四大核心对象之ResultSetHandler

MyBatis会将结果集按照映射配置文件中定义的映射规则,例如节点、resultType属性等,映射成相应的结果对象。这种映射机制就是MyBatis的核心功能之一,可以避免重复的JDBC代码。
在StatementHandler接口在执行完指定的select语句后,会将查询得到的结果集交给ResultSetHandler完成映射处理。ResultSetHandler除了负责映射select语句查询得到的及结果集,还会处理存储过程执行后的输出参数。
ResultSetHandler接口定义如下:

public interface ResultSetHandler {
  // 处理结果集,生成相应的结果对象集合
   List handleResultSets(Statement stmt) throws SQLException;
  // 处理结果集,返回响应的游标对象
   Cursor handleCursorResultSets(Statement stmt) throws SQLException;
  // 处理存储过程的输出参数
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

DefaultResultSetHandler是ResultSetHandler接口的唯一实现。DefaultResultSetHandler的核心字段含义如下:

  private final Configuration configuration;
  private final MappedStatement mappedStatement;
  private final RowBounds rowBounds;
  private final ParameterHandler parameterHandler;
  private final ResultHandler resultHandler;
  private final BoundSql boundSql;
  // TypeHandler注册中心
  private final TypeHandlerRegistry typeHandlerRegistry;
  // 对象工厂
  private final ObjectFactory objectFactory;
  // 反射工厂
  private final ReflectorFactory reflectorFactory;

handleResultSets()方法

通过select语句查询数据库得到的结果集由DefaultResultSetHandler.handleResultSets()方法进行处理,该方法不仅可以处理Statement、PreparedStatement产生的结果集,还可以处理CallbaleStatement代用存储过程产生的多结果集。
DefaultResultSetHandler.handleResultSets()方法的具体如下:

public List handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    //用于保存结果集对象
    final List multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    //statment可能返回多个结果集对象,这里先取出第一个结果集
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    //获取结果集对应resultMap,本质就是获取字段与java属性的映射规则
    List resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);//结果集和resultMap不能为空,为空抛出异常
    while (rsw != null && resultMapCount > resultSetCount) {
     //获取当前结果集对应的resultMap
      ResultMap resultMap = resultMaps.get(resultSetCount);
      //根据映射规则(resultMap)对结果集进行转化,转换成目标对象以后放入multipleResults中
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);//获取下一个结果集
      cleanUpAfterHandlingResultSet();//清空nestedResultObjects对象
      resultSetCount++;
    }
    //获取多结果集。多结果集一般出现在存储过程的执行,存储过程返回多个resultset,
    //mappedStatement.resultSets属性列出多个结果集的名称,用逗号分割;
    //多结果集的处理不是重点,暂时不分析
    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);
  }
 
 

首先来看getFirstResultSet()、getNextResultSet()方法的实现,这两个方法都是JDBC处理多结果集的相关操作。

private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    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;
        }
      }
    }
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }
private ResultSetWrapper getNextResultSet(Statement stmt) {
    // Making this method tolerant of bad JDBC drivers
    try {
      if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
        // Crazy Standard JDBC way of determining if there are more results
        if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
          ResultSet rs = stmt.getResultSet();
          if (rs == null) {
            return getNextResultSet(stmt);
          } else {
            return new ResultSetWrapper(rs, configuration);
          }
        }
      }
    } catch (Exception e) {
      // Intentionally ignored.
    }
    return null;
  }

ResultSetWrapper

上一小节对DefaultResultSetHandler.getFirstResultSet()方法的分析中,可以看到DefaultResultSetHandler在获取ResultSet对象之后,会将其封装成ResultSetWrapper对象再进行处理。ResultSetWrapper是对ResultSet的一层包装,记录了ResultSet的一些元数据,并提供了一系列操作ResultSet的辅助方法。

首先看ResultSetWrapper的核心字段:

你可能感兴趣的:(MyBatis四大核心对象之ResultSetHandler)