MyBatis源码的学习(19)---如何将jdbc的返回结果resultSet处理为我们想要的java类型

 ̄綄美尐妖づ 提交于 2020-01-25 07:04:09

处理结果集的逻辑:ResultSetHandler---->TypeHandler

 @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//这一步完成connection建立,statement对象的创建,参数的赋值操作
      stmt = prepareStatement(handler, ms.getStatementLog());
     //我们今天看者一行,如何将jdbc返回的resultSet对象处理为我们想要的java类型
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
//在 PreparedStatementHandler 类中,我们使用的是默认的预编译的statement
 @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleResultSets(ps);
  }
 public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
//<select>标签的resultMap属性,可以指定多个值,多个值之间用 “,”分割
//我们一般一个seclect指定一个resultMap
    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
//将jdbc返回结果,进行包装。
//对每一列,封装列名,java类型,jdbc类型
    ResultSetWrapper rsw = getFirstResultSet(stmt);
//里面封装的就是我们java的结果类型,也就是我们XML中配置的 resultType或resultMap
//resultType外层是resultMap
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
//进行遍历,赋值
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
//jdbc类型转为java类型
      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++;
      }
    }
// 这一步就是根据list的大小做判断,如果为1,则取第一条数据出来。是一个list套list的结构
//我们的list中的数据:
//User{userCode='10', userName='zzx', createTime=Mon Dec 16 22:42:57 CST 2019, userType='00', mobile='13456879087'}
    return collapseSingleResultList(multipleResults);
  }

 private List<Object> collapseSingleResultList(List<Object> multipleResults) {
    return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
  }

 我们重点看下如何将jdbc类型结果转为java类型:

 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
// 处理嵌套结果映射,我们的级联操作等,一个resultMap中某个java属性
//是另一个resultMap负责映射的
//比如 Student中有一个school属性,school有另一个结果集映射
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {
//新建一个resultHandler对象,对结果进行处理
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//将我们的结果集放入multipleResults这个 list中
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }


public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) { //处理级联sql结果级,嵌套的resultMap
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {//我们是一个普通的结果集,走这个分支
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }


private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
//这一步是做逻辑分页用的,比如我们起始 1,那么会跳过第一行数据,
//从第二行开始。 new RowBound(1,2)
    skipRows(resultSet, rowBounds);
//shouldProcessMoreRows()这个方法是进行判断逻辑分页结束的,比如我们这个应该13行数据,但是
//我们只取从 1开始,俩条数据
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { 
//这块就是我们jdbc遍历取结果的步骤,只不过在这里会做转java类型的操作
      //这个是处理鉴别器标签的,结果集多态。我们这儿不做鉴别器处理
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
//根据反射进行映射,生成一个java的对象。将一行数据转换为一个java类型对象,POJO
//User{userCode='10', userName='zzx', createTime=Mon Dec 16 22:42:57 CST 2019, userType='00', mobile='13456879087'}
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
//将我们的行数据,加入到我们结果集list中 比如查到10条数据,最终
// list.add(0),list.add(1),...这样操作,我们最终得到一个list数据集
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }


/**
 <resultMap id="modelTypeMap" type="com.javartisan.BaseModel">
    <discriminator javaType="java.lang.Integer" column="modelType">
        <case value="1" resultType="com.javartisan.Model1"/>
        <case value="2" resultType="com.javartisan.Model2"/>
    </discriminator>
</resultMap>


**/

可以对比下传统的jdbc的操作:

  rs = statement.executeQuery("select * from test");           
 //执行sql查询语句,返回结果集
            System.out.println("查询结果为:");
           while(rs.next()) {                              
 //循环操作结果集
            string = rs.getString("id") + "——" + rs.getString("name");
            System.out.println(string);
        }

应用反射给java对象赋值的操作:

//将一行数据,应用反射转为java对象,同时给对象属性赋值
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//应用反射,创建一个User对象,这时候属性值还没赋值
    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;
  }


private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    // 通过反射,new一个对象出来,这儿,就是new User() (因为我们返回的java类型是User)
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
  }
// 给属性字段赋值,赋值成功返回 true
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
//MetaObject 里面封装了User{userCode='null', userName='null', createTime=null, userType='null', mobile='null'}
//UnMappedColumnAutoMapping 这里面负责映射关系的维护,jdbc的列名,java的属性名,类型处理器
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
//根据列名找到对应列的值value,比如,我们的usercode列 值为1
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
          // gcode issue #377, call setter on nulls (value is not 'found')
//给属性字段,进行赋值 列名usercode对应的java属性是userCode,给其赋值 
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!