Mybatis-DefaultResultSetHandler(二)源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

DefaultResultSetHandler

  /**
   * 取得构造函数所需的参数值去创建结果对象(自动映射)
   * @param rsw 结果集包装类对象
   * @param resultType 结果对象
   * @param constructorArgTypes 构造函数参数类型集合
   * @param constructorArgs 构造函数参数集合
   * @return 结果对象
   */
  private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
    //获取ResultType的定义的所有构造函数
    final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
    //获取默认构造函数
    final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
    if (defaultConstructor != null) {
      //取得defaultConstructor构造函数所需的参数值去创建结果对象
      return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, defaultConstructor);
    } else {
      //下面代码的用意是找到一个构造函数是所有构造函数参数都有对应的TypeHandler的构造函数来创建结果对象
      //遍历构造函数
      for (Constructor<?> constructor : constructors) {
        //允许构造函数使用TypeHandler
        if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
          // 取得构造函数所需的参数值去创建结果对象
          return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, constructor);
        }
      }
    }
    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
  }

  /**
   * 取得构造函数所需的参数值去创建结果对象
   * @param rsw 结果集包装类对象
   * @param resultType 结果对象类型
   * @param constructorArgTypes 结果对象构造函数参数类型结合
   * @param constructorArgs 结果对象构造函数参数集合
   * @param constructor 构造函数
   * @return 只要有一个构造函数参数对象成功构建,就会使用constructor创建resultType对象。否则返回null
   * @throws SQLException
   */
  private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
    //是否成功构建到了构造函数参数对象的标记
    boolean foundValues = false;
    //遍历构造函数参数
    for (int i = 0; i < constructor.getParameterTypes().length; i++) {
      //获取构造函数参数类型
      Class<?> parameterType = constructor.getParameterTypes()[i];
      //获取列名,TODO 直接获取列名?这样构造函数的参数会和所有列集合的元素顺序一致吗?
      String columnName = rsw.getColumnNames().get(i);
      //获取parmaterType和columnName对应的TypeHandler
      TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
      //从 ResultSet 中取出columnName对应数据,然后转换为 java 对象
      Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
      //将构造函数参数类型添加到构造函数类型集合中
      constructorArgTypes.add(parameterType);
      //将构造函数参数添加到构造函数集合中
      constructorArgs.add(value);
      //只要有一个构造函数参数对象成功构建都会将foundValue设置成true
      foundValues = value != null || foundValues;
    }
    //只要要有一个构造函数参数对象成功构建,就会使用constructor创建resultType对象。否则返回null
    return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }

  /**
   * 获取默认构造函数
   * @param constructors 构造函数数组
   * @return 默认构造函数:如果构造函数只有一个,返回这个唯一的一个。如果有多个构造函数,返回配置了
   *    AutomapConstructor注解的构造函数
   */
  private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {
    //如果构造函数只有一个
    if (constructors.length == 1) {
      //返回第一个
      return constructors[0];
    }
    //遍历构造函数
    for (final Constructor<?> constructor : constructors) {
      //如果构造函数中配置了AutompConstructor注解
      if (constructor.isAnnotationPresent(AutomapConstructor.class)) {
        return constructor;
      }
    }
    return null;
  }

  /**
   * 允许构造函数使用TypeHandler,
   * <p>
   *     如果 {@code constructor} 的每个参数都有对应的列的jdbcType,且存在对应的TypeHander时,
   *     就会返回true;否则返回false
   * </p>
   * @param constructor 构造函数
   * @param jdbcTypes 结果集每个列的jdbc类型
   * @return 允许返回true;否则返回false
   */
  private boolean allowedConstructorUsingTypeHandlers(final Constructor<?> constructor, final List<JdbcType> jdbcTypes) {
    //获取constructor的参数类型数组
    final Class<?>[] parameterTypes = constructor.getParameterTypes();
    //参数类型数组长度不等于jdbc类型长度时
    if (parameterTypes.length != jdbcTypes.size()) {
      return false;
    }
    //遍历参数类型数组
    for (int i = 0; i < parameterTypes.length; i++) {
      //如果不存在parameterType和jdbcType对应的TypeHandler时
      if (!typeHandlerRegistry.hasTypeHandler(parameterTypes[i], jdbcTypes.get(i))) {
        return false;
      }
    }
    return true;
  }

  /**
   * 构建基本类型的结果对象
   * <p>
   *     取出第一列数据转换成基本类型的结果对象
   * </p>
   * @param rsw 结果集包装类对象
   * @param resultMap Mapper.xml的resultMap标签信息封装类对象
   * @param columnPrefix 列名前缀
   * @return 取出第一列数据转换成基本类型的结果对象
   */
  private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    //获取结果对象类型
    final Class<?> resultType = resultMap.getType();
    //列名
    final String columnName;
    //如果 resultMap 子元素映射关系集合 不为空
    if (!resultMap.getResultMappings().isEmpty()) {
      //获取resultMap 子元素映射关系集合
      final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
      //获取第一个resultMap 子元素映射关系
      final ResultMapping mapping = resultMappingList.get(0);
      //构建第一个resultMap 子元素映射关系的列名
      columnName = prependPrefix(mapping.getColumn(), columnPrefix);
    } else {
      //获取第一个列名
      columnName = rsw.getColumnNames().get(0);
    }
    //获取TypeHandler,把columnName的类型解析出来并缓存,如果没有的定义的话,使用jdbc对应的类型。
    final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
    //从 ResultSet 中取出columnName对应数据,然后转换为 java 对象
    return typeHandler.getResult(rsw.getResultSet(), columnName);
  }

  //
  // NESTED QUERY
  //

  /**
   * 获取嵌套查询构造函数参数值
   * @param rs 结果集
   * @param constructorMapping 构造函数参数映射关系
   * @param columnPrefix 列名前缀
   * @return 嵌套查询构造函数参数值
   */
  private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
    //获取select标签Id
    final String nestedQueryId = constructorMapping.getNestedQueryId();
    //查询nestedQueryId的 Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    //获取嵌套查询的参数java类型
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    //构建constructorMapping嵌套查询的参数对象,并将结果赋值到参数对象中
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
    Object value = null;
    if (nestedQueryParameterObject != null) {
      //构建嵌套查询的BoundSql对象
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      //构建嵌套查询的缓存Key
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
      //获取构造函数参数映射关系配置的javaType
      final Class<?> targetType = constructorMapping.getJavaType();
      //构建结果加载器
      final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
      //获取嵌套查询构造函数参数值
      value = resultLoader.loadResult();
    }
    return value;
  }

  /**
   * 构建带有嵌套查询属性的值对象
   * @param rs 结果集对象
   * @param metaResultObject 结果元对象
   * @param propertyMapping 属性映射
   * @param lazyLoader 用来表示需要懒加载的属性集,本质是一个HashMap
   * @param columnPrefix 列名前缀
   * @return 属性对象
   */
  private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    //获取属性映射配置的select标签Id
    final String nestedQueryId = propertyMapping.getNestedQueryId();
    //获取属性映射配置的属性名
    final String property = propertyMapping.getProperty();
    //获取对应的select标签对象
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    //获取select标签对象的参数类型
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    //构建propertyMapping嵌套查询的参数对象,并将结果赋值到参数对象中
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
    Object value = null;
    //如果嵌套查询参数对象不为null
    if (nestedQueryParameterObject != null) {
      //构建嵌套查询的BoundSql对象
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      //创建缓存Key
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
      //获取属性映射配置的java类型
      final Class<?> targetType = propertyMapping.getJavaType();
      //如果执行器缓存中有这个查询的结果
      if (executor.isCached(nestedQuery, key)) {
        //延期加载
        executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
        value = DEFERRED;
      } else {
        //构建结果加载器
        final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
        //如果属性映射配置了懒加载
        if (propertyMapping.isLazy()) {
          //添加加载器到懒加载属性集映射
          lazyLoader.addLoader(property, metaResultObject, resultLoader);
          value = DEFERRED;
        } else {
          //如果没有配置懒加载
          //加载结果
          value = resultLoader.loadResult();
        }
      }
    }
    return value;
  }

  /**
   * 构建 {@code resultMapping} 嵌套查询的参数对象,并将结果赋值到参数对象中
   * @param rs 结果集
   * @param resultMapping resultMap 子元素映射关系
   * @param parameterType 参数类型
   * @param columnPrefix 列名前缀
   * @return  {@code resultMapping} 嵌套查询的参数对象
   */
  private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    //是否存在组合ResultMaping列表
    if (resultMapping.isCompositeResult()) {
      //构建嵌套的结果映射的参数对象,并将结果赋值到参数对象中。
      // 嵌套结果映射是指resultMapping下的resultMaping对象集合,通过resultMapping.getComposites()获取
      return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
    } else {
      //构建简单类型的参数对象,并将结果赋值到参数对象中
      return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
    }
  }

  /**
   * 构建简单类型的参数对象,并将结果赋值到参数对象中
   * @param rs 结果集
   * @param resultMapping resultMap 子元素映射关系
   * @param parameterType 参数类型
   * @param columnPrefix 列名前缀
   * @return 对应 {@code resultMapping} 的参数对象
   */
  private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    final TypeHandler<?> typeHandler;
    //如果存在parameterType对应的TypeHandler
    if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
      //获取parameterType对应的TypeHandler
      typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
    } else {
      //没有找到对应的TypeHandler时,就用未知类型的TypeHandler
      /**
       * UnknownTypeHandler:在{@link BaseTypeHandler}的抽象方法中根据
       * 返回的结果集提供的列去获取对应的TypeHandler时候,
       * 在获取不到的情况下,就会使用{@link ObjectTypeHandler}处理
       */
      typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
    }
    //从 ResultSet 中取出columnName对应数据,然后转换为 java 对象
    return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
  }

  /**
   * 构建嵌套的结果映射的参数对象,并将结果赋值到参数对象中
   * @param rs 结果集
   * @param resultMapping resultMap 子元素映射关系对象
   * @param parameterType 参数类型
   * @param columnPrefix 列名前缀
   * @return 如果未能将值赋进parameterObject中,则返回null;否则返回已将结果赋值到参数对象的参数对象
   */
  private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    //实例化parameterType类型对象
    final Object parameterObject = instantiateParameterObject(parameterType);
    //构建参数对象的元对象
    final MetaObject metaObject = configuration.newMetaObject(parameterObject);
    //已将值赋进parameterObject中的标记
    boolean foundValues = false;
    //遍历嵌套的结果映射
    for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
      //获取参数对象对应该嵌套映射结果的property的setter参数类型
      final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
      //获取参数对象对应该嵌套映射结果的property的setter参数类型的TypeHandler对象
      final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
      //用于从rs中取出column对应的数据转换为 java 对象
      final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
      // issue #353 & #560 do not execute nested query if key is null
      if (propValue != null) {
        //将propValue赋值到parameterObject中
        metaObject.setValue(innerResultMapping.getProperty(), propValue);
        foundValues = true;
      }
    }
    //如果未能将值赋进parameterObject中,则返回null;否则返回参数对象
    return foundValues ? parameterObject : null;
  }

  /**
   * 实例化参数对象
   * @param parameterType 参数类型
   * @return 参数对象
   */
  private Object instantiateParameterObject(Class<?> parameterType) {
    //如果参数类型为null
    if (parameterType == null) {
      //返回新的HashMap对象
      return new HashMap<>();
      /**
       * ParamMap:  只接受{@link String}类型的key,并且重写了{@link HashMap#get(Object)},
       * 获取 在{@link ParamMap}没有的key会抛出{@link BindingException}
       */
      //如果参数类型为ParamMap时
    } else if (ParamMap.class.equals(parameterType)) {
      //返回新的HashMap对象
      return new HashMap<>(); // issue #649
    } else {
      //使用对象工厂创建parameterType对象
      //如果objectFactory为DefaultObjectFactory实例,则是通过无参构造方法创建对象
      return objectFactory.create(parameterType);
    }
  }

  //
  // DISCRIMINATOR
  //

  /**
   * 逐层解析{@code resultMap}鉴别器,取得最终的ResultMap标签对象
   * @param rs 结果集
   * @param resultMap Mapper.xml的resultMap标签信息封装类
   * @param columnPrefix 列名前缀
   * @return 嵌套中的最终resultMap对象
   */
  public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
    //记录已经处理过的ResultMap的id
    Set<String> pastDiscriminators = new HashSet<>();
    //获取<resultMap>中的<discriminator>节点对象,discriminator是一个鉴别器节点,以下有关于鉴别器节点的说明
    Discriminator discriminator = resultMap.getDiscriminator();
    //当该鉴别器对象不为null时,进入循环
    while (discriminator != null) {
      //获取记录中对应列的值,其中会使用相应的类型处理器对象将该列值转换成java类型,一般是String类型
      final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
      /**
       * 根据该列值获取对应的ResultMap的id,因为这里是处理嵌套的情况,
       * 所以在<discriminator>节点下又有<resultMap>节点,如果不嵌套就一般是
       *  <result>或者<id>节点
       */
      final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
      //查找全局配置信息中是否有该嵌套的resultMap节点的id
      if (configuration.hasResultMap(discriminatedMapId)) {
        //如果有该id,根据该id在全局配置信息中获取该resultMap对象
        resultMap = configuration.getResultMap(discriminatedMapId);
        ///记录当前鉴别器对象
        Discriminator lastDiscriminator = discriminator;
        //获取resultMap对象中的鉴别器对象
        discriminator = resultMap.getDiscriminator();
        if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
          break;
        }
      } else {
        break;
      }
    }
    return resultMap;
  }

  /**
   * 获取Discriminator的值对象,其中会使用相应的类型处理器对象将该列值转换成java类型
   * @param rs 结果集
   * @param discriminator 鉴别器对象
   * @param columnPrefix 列前缀
   * @return Discriminator的值对象
   */
  private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
    final ResultMapping resultMapping = discriminator.getResultMapping();
    final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
    return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
  }

  /**
   * 拼接前缀与列名
   * @param columnName 列名
   * @param prefix 前缀
   * @return 拼接前缀与列名后的结果
   */
  private String prependPrefix(String columnName, String prefix) {
    if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
      return columnName;
    }
    return prefix + columnName;
  }

  //
  // HANDLE NESTED RESULT MAPS
  //

  /**
   * 为嵌套的ResultMap标签对象,将构建出来的结果对象加入到reusltHandler中
   * @param rsw 结果集包装类
   * @param resultMap Mapper.xml的resultMap标签信息封装类对象
   * @param resultHandler 结果处理器器
   * @param rowBounds Mybatis的分页对象
   * @param parentMapping resultMap标签的子标签信息封装类对象
   */
  private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    //构建一个默认的结果上下文
    final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    //获取结果集
    ResultSet resultSet = rsw.getResultSet();
    //跳过rowBounds.offset记录数
    skipRows(resultSet, rowBounds);
    //获取上一次嵌套的resultMap对象
    Object rowValue = previousRowValue;
    //是否应该读取更多结果行,且结果集未关闭,且结果集的游标还可以获取下一个结果行
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      ///获取所有嵌套中的最终resultMap对象
      final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      //将该resultMap对象中的元素构建成CacheKey对象
      final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
      //查找该CacheKey对象映射的嵌套的resultMap对象与结果集构建出来的结果对象
      Object partialObject = nestedResultObjects.get(rowKey);
      // issue #577 && #542
      //如果<select>标签嵌套或者分组了
      /**
       * ResultOrdered:
       * 如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,
       * 就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。
       * 默认值:false。
       */
      //TODO 待解析
      if (mappedStatement.isResultOrdered()) {
        //如果嵌套映射中没有该resultMap对象且上一次嵌套的resultMap对象不为null
        if (partialObject == null && rowValue != null) {
          //清空嵌套resultMap映射
          nestedResultObjects.clear();
          /**
           * 保存对象,如果parentMaping不为null,就将结果对象添加到parentMapping
           * 的metaObject中;否则,调用结果处理器,将结果对象添加到结果处理器中
           */
          storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
        /**
         * 根据rsw和resultMap的配置构建结果对象,并遍历resultMap配置的属性结果映射,
         *  构建出属性结果对象赋值到resultMap相应的属性中
         */
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
      } else {
        /**
         * 根据rsw和resultMap的配置构建结果对象,并遍历resultMap配置的属性结果映射,
         *  构建出属性结果对象赋值到resultMap相应的属性中
         */
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
        //如果缓存的结果对象为null
        if (partialObject == null) {
          /**
           * 保存对象,如果parentMaping不为null,就将结果对象添加到parentMapping
           * 的metaObject中;否则,调用结果处理器,将结果对象添加到结果处理器中
           */
          storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
      }
    }
    /**
     * isResultOrderd: 如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,
     *  就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。
     * shouldProcessMoreRows:是否还有结果需要处理
     */
    if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
      /**
       * 保存对象,如果parentMaping不为null,就将结果对象添加到parentMapping
       * 的metaObject中;否则,调用结果处理器,将结果对象添加到结果处理器中
       */
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
      //将上一个结果对象清除
      previousRowValue = null;
    } else if (rowValue != null) {
      //将当前结果赋值到上一个结果对象中
      previousRowValue = rowValue;
    }
  }

  //
  // GET VALUE FROM ROW FOR NESTED RESULT MAP
  //

  /**
   * 根据 {@code rsw} 和 {@code resultMap} 的配置构建结果对象,并遍历 {@code resultMap}配置
   * 的属性结果映射,构建出属性结果对象赋值到 {@code resultMap} 相应的属性中
   * @param rsw 结果集包装类对象
   * @param resultMap resultMap标签对象
   * @param combinedKey 缓存Key
   * @param columnPrefix 列名前缀
   * @param partialObject {@code resultMap} 结果对象
   * @return 根据 {@code rsw} 和 {@code resultMap} 的配置构建出来的结果对象
   * @throws SQLException
   */
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
    //获取resultMap配置Id
    final String resultMapId = resultMap.getId();
    //将嵌套的resultMap对象与结果集构建出来的java类型对象赋值临时变量rowVale
    Object rowValue = partialObject;
    //如果结果对象不为null
    if (rowValue != null) {
      //构建出rowValue的元对象
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      //将resultMap标签对象Id和结果对象加入的ancestorObjects中
      putAncestor(rowValue, resultMapId);
      /**
       * 遍历resultMap的属性结果映射,如果有属性结果映射有配置嵌套的ResultMapId,
       * 但没有配置复杂类型的结果集名时【ResultSet属性】,就会获取resultMapId对应ResultMap对象,
       * 再根据rsw 和 ResultMap对象 构建出结果对象,然后将结果对象加入到metaObject
       */
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
      //成功结果对象加入到metaObject后,就将结果对象从ancestorObject中移除
      ancestorObjects.remove(resultMapId);
    } else {
      //新建一个 用来表示需要懒加载的属性集,本质是一个HashMap
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      //根据rsw和resultMap的配置构建结果对象
      rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
      //结果对象不为null而且判断有没有对应的TypeHandler
      if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        //构建rowValue元对象
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        //当前结果对象是否使用了非无参构造函数进行构建
        boolean foundValues = this.useConstructorMappings;
        //是否可以应用自动映射
        if (shouldApplyAutomaticMappings(resultMap, true)) {
          //对未能被映射列名映射关系集合进行尝试赋值,将结果集对应数据赋值到结果对象对应的属性中
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        //根据结果集和属性映射构建对应的目标对象,并赋值到结果对象中
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        //将resultMap标签对象Id和结果对象加入的ancestorObjects
        putAncestor(rowValue, resultMapId);
        /**
         * 遍历resultMap的属性结果映射,如果有属性结果映射有配置嵌套的ResultMapId,
         * 但没有配置复杂类型的结果集名时【ResultSet属性】,就会获取resultMapId对应ResultMap对象,
         * 再根据rsw和 ResultMap对象 构建出结果对象,然后将结果对象加入到
         */
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
        //成功结果对象加入到metaObject后,就将结果对象从ancestorObject中移除
        ancestorObjects.remove(resultMapId);
        //如果存在需要懒加载的属性对象的懒加载器
        foundValues = lazyLoader.size() > 0 || foundValues;
        /**
         当返回行的所有列都是空时,MyBatis默认返回 null。
         * 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2)
         */
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
      }
      //将结果对象加入到nestedResultObject映射队列中,指定健名为combindeKey
      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        nestedResultObjects.put(combinedKey, rowValue);
      }
    }
    //返回结果对象
    return rowValue;
  }

  /**
   * 将resultMap标签对象Id和结果对象加入的{@link #ancestorObjects}
   * @param resultObject 结果对象
   * @param resultMapId resultMap标签对象的Id
   */
  private void putAncestor(Object resultObject, String resultMapId) {
    ancestorObjects.put(resultMapId, resultObject);
  }

  //
  // NESTED RESULT MAP (JOIN MAPPING)
  //

  /**
   * 遍历 {@code resultMap} 的属性结果映射,如果有属性结果映射有配置嵌套的ResultMapId,
   * 但没有配置复杂类型的结果集名时【ResultSet属性】,就会获取resultMapId对应ResultMap对象,
   * 再根据 {@code rsw} 和 ResultMap对象 构建出结果对象,然后将结果对象加入到
   * {@code metaObject}中
   * @param rsw 结果集包装类对象
   * @param resultMap resultMap标签对象
   * @param metaObject 结果元对象
   * @param parentPrefix 父级列名
   * @param parentRowKey 父级列名缓存key
   * @param newObject 结果对象是否是新对象
   * @return 只要有一个属性结果对象加入到metaObject中,就会设置为true
   */
  private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
    //成功赋值标记,只要有一个属性结果对象加入到metaObject中,就会设置为true
    boolean foundValues = false;
    //遍历reusltMap下的属性结果映射
    for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
      //获取嵌套的resultMapId
      final String nestedResultMapId = resultMapping.getNestedResultMapId();
      //如果配置了嵌套的resultMapId但没有配置复杂类型的结果集名
      if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
        try {
          //获取列前缀
          final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
          //获取嵌套的resultMap标签对象
          final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
          //如果结果属性映射没有配置列名前缀
          if (resultMapping.getColumnPrefix() == null) {
            // try to fill circular reference only when columnPrefix
            // is not specified for the nested result map (issue #215)
            //  只有当列前缀没有指定嵌套映射结果时试图填补循环引用
            //获取nesetedResultMapId对应的结果对象
            Object ancestorObject = ancestorObjects.get(nestedResultMapId);
            //如果结果对象不为null
            if (ancestorObject != null) {
              //如果metaObject对应的结果对象是个新的对象
              if (newObject) {
                //将ancestorObject添加到元对象的{@code resultMapping}配置的属性中
                linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
              }
              //跳过
              continue;
            }
          }
          /**
           * 将 resultMap标签对象配置的信息 和 结果集包装对象对应数据 和 列名前缀
           * 作为构建CacheKey的一部分,从而构建构建成CacheKey对象
           */
          final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
          //将两个缓存Key组合起来,形成一个新的缓存Key
          final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
          //获取combindKey对应的结果对象
          Object rowValue = nestedResultObjects.get(combinedKey);
          //如果结果对不为null
          boolean knownValue = rowValue != null;
          /**
           * 如果resultMapping为集合类则进行实例化返回,当metaObject存在resultMapping对应的
           * 属性对象时,并不会实例化,而是判断是否是集合类型,是就返回该属性对象,否则返回null
           */
          instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
          //检查resultMapping 与 rsw 之间的 的合法性
          if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
            rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
            if (rowValue != null && !knownValue) {
              //将rowValue添加到metaObject的resultMapping配置的属性中
              linkObjects(metaObject, resultMapping, rowValue);
              //只要有一个属性结果对象加入到metaObject中,就会设置为true
              foundValues = true;
            }
          }
        } catch (SQLException e) {
          throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
        }
      }
    }
    return foundValues;
  }

  /**
   * 获取列前缀
   * @param parentPrefix 父级列前缀
   * @param resultMapping 结果映射
   * @return 列前缀(父级列前缀+子结果映射前缀)
   */
  private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
    final StringBuilder columnPrefixBuilder = new StringBuilder();
    if (parentPrefix != null) {
      //添加父级列前缀
      columnPrefixBuilder.append(parentPrefix);
    }
    if (resultMapping.getColumnPrefix() != null) {
      //添加reusltMapping的类名前缀
      columnPrefixBuilder.append(resultMapping.getColumnPrefix());
    }
    //转化成大写返回
    return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
  }

  /**
   * 检查 {@code resultMapping} 与 {@code rsw} 之间的 的合法性
   * @param resultMapping 结果属性映射
   * @param columnPrefix 列名前缀
   * @param rsw 结果集包装类
   * @return
   * <ul>
   *     <li>如果配置了不为null的列名,只要有一个指定列名在结果集不为null都会返回true,
   *     否则返回false</li>
   *     <li>如果没有配置不为null的列名,但有配置了列名前缀,只有有一个列名是以列名前缀开头的,
   *     否则返回false</li>
   *     <li>默认情况是返回true</li>
   * </ul>
   * @throws SQLException
   */
  private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw) throws SQLException {
    //获取不能为null的列名
    Set<String> notNullColumns = resultMapping.getNotNullColumns();
    //如果配置了不能为null的列名
    if (notNullColumns != null && !notNullColumns.isEmpty()) {
      //获取结果集
      ResultSet rs = rsw.getResultSet();
      //遍历不能为null的列名
      for (String column : notNullColumns) {
        //获取 拼接前缀和列名后完整列名 对应的对象
        rs.getObject(prependPrefix(column, columnPrefix));
        //如果该完整列名不为null
        if (!rs.wasNull()) {
          return true;
        }
      }
      return false;
      //如果列名前缀不为null
    } else if (columnPrefix != null) {
      //遍历结果集包装类对象的所有列名
      for (String columnName : rsw.getColumnNames()) {
        //如果有一个列名是以列名前缀开头的
        if (columnName.toUpperCase().startsWith(columnPrefix.toUpperCase())) {
          return true;
        }
      }
      return false;
    }
    return true;
  }

  /**
   * 获取嵌套的resultMap标签对象
   * @param rs 结果集
   * @param nestedResultMapId 嵌套的resultMapId
   * @param columnPrefix 列名前缀
   * @return 嵌套的resultMap标签对象
   */
  private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
    //获取nestedResultMapId对应的resultMap标签对象
    ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
    //逐层解析nestedResultMap鉴别器,取得最终的ResultMap标签对象
    return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
  }

  //
  // UNIQUE RESULT KEY
  //

  /**
   * 将 resultMap标签对象配置的信息 和 结果集包装对象对应数据 和 列名前缀
   *  作为构建CacheKey的一部分,从而构建构建成CacheKey对象
   * @param resultMap resultMap标签对象
   * @param rsw 结果集包装对象
   * @param columnPrefix 列名前缀
   */
  private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
    //创建CacheKey对象
    final CacheKey cacheKey = new CacheKey();
    //将resultMap的id作为Cachekey对象的一部分
    cacheKey.update(resultMap.getId());
    //查找resultMap的ResultMapping对象集合
    List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
    //如果该ResultMapping对象集合为空
    if (resultMappings.isEmpty()) {
      //如果ResultMap对象为Map接口的实现类
      if (Map.class.isAssignableFrom(resultMap.getType())) {
        //由结果集中的所有列名以及当前记录行的所有列值一起构成CacheKey对象
        createRowKeyForMap(rsw, cacheKey);
      } else {
        //如果ResultMap对象不是Map接口的实现类
        //由结果集中未映射的列名以及它们在当前记录中的对应列值一起构成CacheKey对象
        createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
      }
      //如果该ResultMapping对象集合不为空
    } else {
      //由resultMappings集合中的列名以及它们在当前记录行中相应的列值一起构成CacheKey
      createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
    }
    //如果通过上面的查找没有找到任何列参与构成CacheKey对象,则返回NULL_CACHE_KEY对象
    if (cacheKey.getUpdateCount() < 2) {
      return CacheKey.NULL_CACHE_KEY;
    }
    return cacheKey;
  }

  /**
   * 将两个缓存Key组合起来,形成成一个新的缓存Key
   * @param rowKey 缓存Key
   * @param parentRowKey 父级缓存Key
   * @return 两个缓存Key组合起来的一个新的缓存Key
   */
  private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
    //如果两个缓存Key都有更新记录
    if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
      //组合缓存Key
      CacheKey combinedKey;
      try {
        //克隆rowKey为组合缓存Key的实例
        combinedKey = rowKey.clone();
      } catch (CloneNotSupportedException e) {
        throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);
      }
      //将parantRowKey作为组合缓存key的一部分
      combinedKey.update(parentRowKey);
      return combinedKey;
    }
    return CacheKey.NULL_CACHE_KEY;
  }

  /**
   * 查找ResultMapping对象集合
   * @param resultMap Mapper.xml的resultMap标签信息封装类对象
   * @return {@code resultMap} 的ResultMapping对象集合
   */
  private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
    //从resultMap对象中获取idResultMappings集合,该集合记录<idArg>、<id>节点对应的ResultMapping对象
    List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
    //如果该集合为空
    if (resultMappings.isEmpty()) {
      //获取resultMap对象中记录了除<id*>节点之外的ResultMapping对象
      resultMappings = resultMap.getPropertyResultMappings();
    }
    return resultMappings;
  }

  /**
   * 如果该ResultMapping对象集合不为空
   * @param resultMap Mapper.xml的resultMap标签信息封装类对象
   * @param rsw 结果集包装类
   * @param cacheKey 缓存Key
   * @param resultMappings ResultMap的子元素映射关系
   * @param columnPrefix 列名前缀
   */
  private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
    //遍历resultMappings集合
    for (ResultMapping resultMapping : resultMappings) {
      if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
        // Issue #392
        //从全局配置信息中获取该id对应的ResultMap对象
        final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
        //递归该嵌套ResultMap对象
        createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
            prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
        //如果resultMapping对象的嵌套查询id为null
      } else if (resultMapping.getNestedQueryId() == null) {
        //拼装columnPrefix+resultMapping.getColumn()为column字符串
        final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
        //获取resultMapping的类型处理器对象
        final TypeHandler<?> th = resultMapping.getTypeHandler();
        //获取结果集的映射列名集合
        List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        // Issue #114
        //如果column不为null且列名集合中包含转换为大写的column
        if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
          //通过类型处理器获取结果集中该column对应的Java对象(值)
          final Object value = th.getResult(rsw.getResultSet(), column);
          //如果该值不为null或者全局配置信息中允许返回空实例
          /**
           *  ReturnInstanceForEmptyRow:
           *  当返回行的所有列都是空时,MyBatis默认返回 null。
           *  当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2)
           */
          if (value != null || configuration.isReturnInstanceForEmptyRow()) {
            cacheKey.update(column);
            cacheKey.update(value);
          }
        }
      }
    }
  }

  /**
   * 由结果集中未映射的列名以及它们在当前记录中的对应列值一起构成CacheKey对象
   * @param resultMap Mapper.xml的resultMap标签信息封装类对象
   * @param rsw 结果集包装类对象
   * @param cacheKey 缓存key对象
   * @param columnPrefix 列名前缀
   */
  private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
    //获取resultMap对象的反射原类型对象(包含类所有的方法,属性,构造器等等)
    final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
    //获取结果集的没有映射关系的列名集合
    List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    for (String column : unmappedColumnNames) {
      String property = column;
      if (columnPrefix != null && !columnPrefix.isEmpty()) {
        // When columnPrefix is specified, ignore columns without the prefix.
        // 如果将每列转化为大写后以列前缀开头
        if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          //取出列前缀之后的字符串
          property = column.substring(columnPrefix.length());
        } else {
          continue;
        }
      }
      //如果ResultMap类中有该属性
      //MapUnderscoreToCamelCase:是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
      if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
        //从结果集中获取该列名对应的值
        String value = rsw.getResultSet().getString(column);
        //如果该值不为null
        if (value != null) {
          //将列名与值分别作为cacheKey的一部分
          cacheKey.update(column);
          cacheKey.update(value);
        }
      }
    }
  }

  /**
   * 由结果集中的所有列名以及当前记录行的所有列值一起构成CacheKey对象
   * @param rsw 结果集包装类
   * @param cacheKey 缓存Key
   */
  private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
    //获取结果集中的列名集合
    List<String> columnNames = rsw.getColumnNames();
    //遍历该集合
    for (String columnName : columnNames) {
      //获取结果集中每一列对应的值
      final String value = rsw.getResultSet().getString(columnName);
      //如果该值不为null
      if (value != null) {
        //将列名与值分别作为cacheKey的一部分
        cacheKey.update(columnName);
        cacheKey.update(value);
      }
    }
  }

  /**
   * 将{@code rowValue}添加到元对象的{@code resultMapping}配置的属性中
   * @param metaObject 元对象
   * @param resultMapping 属性映射
   * @param rowValue 上一次嵌套的resultMap对象所构建出来的对象
   */
  private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
    /**
     * 如果resultMapping为集合类则进行实例化返回,当metaObject存在resultMapping对应的
     *  属性对象时,并不会实例化,而是判断是否是集合类型,是就返回该属性对象,否则返回null
     */
    final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
    //集合属性对象不为null
    if (collectionProperty != null) {
      //构建collectionProperty的元对象
      final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
      //将rowValue添加到conllectionProperty中
      targetMetaObject.add(rowValue);
    } else {
      //如果返回的集合对象为null,表示resultMapping对象不为集合
      //直接将rowValue赋值进元对象的resultMapping配置的属性名中
      metaObject.setValue(resultMapping.getProperty(), rowValue);
    }
  }

  /**
   * 如果{@code resultMapping}为集合类则进行实例化返回,当metaObject存在resultMapping对应的
   * 属性对象时,并不会实例化,而是判断是否是集合类型,是就返回该属性对象,否则返回null
   * @param resultMapping 结果属性映射
   * @param metaObject 结果元对象
   * @return 如果{@code resultMapping}为集合类则进行实例化返回,否则返回null
   */
  private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
    //获取结果属性映射配置的属性名
    final String propertyName = resultMapping.getProperty();
    //获取属性名在元对象中对应属性对象
    Object propertyValue = metaObject.getValue(propertyName);
    //如果属性对象为null
    if (propertyValue == null) {
      //获取结果属性映射配置的java类型
      Class<?> type = resultMapping.getJavaType();
      //如果java类型为null
      if (type == null) {
        //从元对象中获取propertyName对应的setter方法的参数类型
        type = metaObject.getSetterType(propertyName);
      }
      try {
        //如果type属于集合类型
        if (objectFactory.isCollection(type)) {
          /**
           * 创建type对应的对象,如果是List,默认是创建ArrayList,想了解更多,
           * 可以查看DefaultObjectFactory.resolveInterface(Class<?> type)方法
           */
          propertyValue = objectFactory.create(type);
          //将propertyValue设置到元对象
          metaObject.setValue(propertyName, propertyValue);
          return propertyValue;
        }
      } catch (Exception e) {
        throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
      }
      //如果属性对象的类型属于集合类型
    } else if (objectFactory.isCollection(propertyValue.getClass())) {
      return propertyValue;
    }
    //到这来,就是属性对象不属于集合类型,直接返回null
    return null;
  }

  /**
   * 判断有没有对应的TypeHandler
   * @param rsw 结果集包装类对象
   * @param resultType 结果对象类型
   * @return ture表示有,false表示没有
   */
  private boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {
    //当结果集的列数只有一个
    if (rsw.getColumnNames().size() == 1) {
      //用更加精确的方法判断是否存在对应的TypeHandler
      return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));
    }
    //判断有没有resultType对应的TypeHandler
    return typeHandlerRegistry.hasTypeHandler(resultType);
  }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容