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> constructorArgTypes, List 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> constructorArgTypes, List 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,
   * 

* 如果 {@code constructor} 的每个参数都有对应的列的jdbcType,且存在对应的TypeHander时, * 就会返回true;否则返回false *

* @param constructor 构造函数 * @param jdbcTypes 结果集每个列的jdbc类型 * @return 允许返回true;否则返回false */ private boolean allowedConstructorUsingTypeHandlers(final Constructor constructor, final List 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; } /** * 构建基本类型的结果对象 *

* 取出第一列数据转换成基本类型的结果对象 *

* @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 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 pastDiscriminators = new HashSet<>(); //获取中的节点对象,discriminator是一个鉴别器节点,以下有关于鉴别器节点的说明 Discriminator discriminator = resultMap.getDiscriminator(); //当该鉴别器对象不为null时,进入循环 while (discriminator != null) { //获取记录中对应列的值,其中会使用相应的类型处理器对象将该列值转换成java类型,一般是String类型 final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix); /** * 根据该列值获取对应的ResultMap的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 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 //如果