美文网首页mybatis
MyBatis四大核心对象之ResultSetHandler

MyBatis四大核心对象之ResultSetHandler

作者: 施智沂 | 来源:发表于2020-04-06 14:25 被阅读0次

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

    public interface ResultSetHandler {
      // 处理结果集,生成相应的结果对象集合
      <E> List<E> handleResultSets(Statement stmt) throws SQLException;
      // 处理结果集,返回响应的游标对象
      <E> Cursor<E> 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<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
        //用于保存结果集对象
        final List<Object> multipleResults = new ArrayList<>();
    
        int resultSetCount = 0;
        //statment可能返回多个结果集对象,这里先取出第一个结果集
        ResultSetWrapper rsw = getFirstResultSet(stmt);
        //获取结果集对应resultMap,本质就是获取字段与java属性的映射规则
        List<ResultMap> 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

        本文链接:https://www.haomeiwen.com/subject/jtqbphtx.html