zoukankan      html  css  js  c++  java
  • Mybatis ResultMap复合映射使用以及源码分析

     我们知道在mybatis中可以针对一列值作为入参进行嵌套查询,那么如果入参为多个时该如何处理呢? mybatis支持复合映射,下面通过示例代码看看复合映射的使用
     <resultMap id="postLiteMap2NestedWithSelect" type="org.apache.ibatis.domain.blog.BlogLite">
        <id column="blog_id" property="id" />
        <collection property="posts" ofType="org.apache.ibatis.domain.blog.PostLite">
          <constructor>
              <arg javaType="org.apache.ibatis.domain.blog.PostLiteId" column="{id=id}" select="selectPostLiteId" />
              <arg javaType="_int" column="blog_id"/>
          </constructor>
        </collection>
      </resultMap>
    
      <mapper namespace="org.apache.ibatis.domain.blog.mappers.PostMapper">
      <resultMap id="postLiteIdMap" type="org.apache.ibatis.domain.blog.PostLiteId">
          <constructor>
              <idArg javaType="_int" column="id"/>
          </constructor>
      </resultMap>
    
    <select id="selectPostLite2NestedWithSelect" resultMap="postLiteMap2NestedWithSelect">
          select id, 1 as blog_id from post where blog_id is not null
     </select>
    <select id="selectPostLiteId" resultMap="postLiteIdMap">
          select ${id} as id from (values(0)) as t
     </select>
    

      

    查询
    List<BlogLite> posts = session.selectList("org.apache.ibatis.domain.blog.mappers.PostMapper.selectPostLite2NestedWithSelect");



    这是怎样的一个处理过程呢?下面看看时序图
     
     
    下面通过代码看看Mybatis是如何处理的

     public ResultMapping buildResultMapping(
          Class<?> resultType,
          String property,
          String column,
          Class<?> javaType,
          JdbcType jdbcType,
          String nestedSelect,
          String nestedResultMap,
          String notNullColumn,
          String columnPrefix,
          Class<? extends TypeHandler<?>> typeHandler,
          List<ResultFlag> flags,
          String resultSet,
          String foreignColumn,
          boolean lazy) {
        //
        Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
        //类型处理器
        TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
        //解析混合列
        List<ResultMapping> composites = parseCompositeColumnName(column);
        //构建ResultMapping
        return new ResultMapping.Builder(configuration, property, column, javaTypeClass)
            .jdbcType(jdbcType)
                //对嵌套查询ID进行namespace处理
            .nestedQueryId(applyCurrentNamespace(nestedSelect, true))
                //对嵌套ResultMap进行namespace处理
            .nestedResultMapId(applyCurrentNamespace(nestedResultMap, true))
            .resultSet(resultSet)
            .typeHandler(typeHandlerInstance)
            .flags(flags == null ? new ArrayList<ResultFlag>() : flags)
            .composites(composites)
            .notNullColumns(parseMultipleColumnNames(notNullColumn))
            .columnPrefix(columnPrefix)
            .foreignColumn(foreignColumn)
            .lazy(lazy)
            .build();
      }
    
    private List<ResultMapping> parseCompositeColumnName(String columnName) {
        List<ResultMapping> composites = new ArrayList<ResultMapping>();
        //如果columnName不为null 同时colunmnName中含有"=" 或者含有","号
        if (columnName != null && (columnName.indexOf('=') > -1 || columnName.indexOf(',') > -1)) {
          //分割字符串
          StringTokenizer parser = new StringTokenizer(columnName, "{}=, ", false);
          while (parser.hasMoreTokens()) {
            //获取属性
            String property = parser.nextToken();
            //获取列
            String column = parser.nextToken();
            //构建复合的ResultMapping
            ResultMapping complexResultMapping = new ResultMapping.Builder(
                configuration, property, column, configuration.getTypeHandlerRegistry().getUnknownTypeHandler()).build();
            composites.add(complexResultMapping);
          }
        }
        return composites;
      }
    

      

    这样得到的结果是:
     
    至此可以发现{id=id}被解析为了一个复合resultMapping那么在使用的时候又是如何处理的呢?
     
    在DefaultResultSetHandler中对于构造方法中的嵌套查询处理如下,如果配置的是复合映射在处理复合映射的内部映射
    //获取嵌套查询构造参数的值
      private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
        //嵌套查询ID
        final String nestedQueryId = constructorMapping.getNestedQueryId();
        //嵌套查询MappedStatement
        final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
        //嵌套查询参数类型
        final Class nestedQueryParameterType = nestedQuery.getParameterMap().getType();
        //获取嵌套查询入参值
        final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
        Object value = null;
        if (nestedQueryParameterObject != null) {
          final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
          final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
          final Class targetType = constructorMapping.getJavaType();
          final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
          value = resultLoader.loadResult();
        }
        return value;
      }
    
     private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class parameterType, String columnPrefix) throws SQLException {
        //如果是复合映射
        if (resultMapping.isCompositeResult()) {
          return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
        } else {
          return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
        }
      }
    
     private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class parameterType, String columnPrefix) throws SQLException {
        //创建参数对象
        final Object parameterObject = instantiateParameterObject(parameterType);
        final MetaObject metaObject = configuration.newMetaObject(parameterObject);
        boolean foundValues = false;
        //遍历复合结果映射
        for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
          //获取参数类型
          final Class propType = metaObject.getSetterType(innerResultMapping.getProperty());
          //获取类型处理器
          final TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(propType);
          //获取值
           final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
          // 如果参数值不为null则设置到参数对象
          if (propValue != null) {
            metaObject.setValue(innerResultMapping.getProperty(), propValue);
            foundValues = true;
          }
        }
        return foundValues ? parameterObject : null;
      }
    

      

    此时获取到的入参 id值为1 ,同样在其它嵌套查询中也可以使用复合映射
      
    <resultMap id="addressMapper"
        type="org.apache.ibatis.submitted.column_prefix.Address">
        <constructor>
          <idArg column="id" javaType="int" />
          <arg column="state" javaType="string" />
        </constructor>
        <result property="city" column="city" />
        <result property="hasPhone" column="has_phone" />
        <association property="stateBird" select="selectStateBird"
          column="state" />
        <association property="zip" select="selectZip"
          column="{state=state,city=city}" />
        <association property="phone1" select="selectPhone"
          column="phone1_id" />
        <association property="phone2" select="selectPhone"
          column="phone2_id" />
        <discriminator column="addr_type" javaType="int">
          <case value="1"
            resultType="org.apache.ibatis.submitted.column_prefix.AddressWithCaution">
            <result property="caution" column="caution" />
          </case>
        </discriminator>
      </resultMap>
    

      

  • 相关阅读:
    美女检测器
    汉字动画程序的原理
    值类型不是值类型(ValueType is NOT a Value Type):闲谈.Net类型
    PowerShell 简介
    Visual Studio 2012 RC 发布
    使用 MvcMiniProfiler 监控EF 4.1 with MySQL Provider
    NuGet安装及简单使用
    发布自己的NuGet程序
    Qizmt 单机及分布式部署注意事项
    JDynamic :支持Json反序列化为Dynamic对象
  • 原文地址:https://www.cnblogs.com/wei-zw/p/9001906.html
Copyright © 2011-2022 走看看