首页 > 其他分享 >mybatis 中resultMap原理

mybatis 中resultMap原理

时间:2022-08-31 00:55:31浏览次数:67  
标签:null String resultMap resultMapNode mybatis 原理 rsw foundValues

  mybatis中从数据库中查询出数据,然后转化成对象的过程中起了关键作用的一个类是ResultMap.他定义了查询的结果最终转化成了哪个类的对象,并且定义了每个对象的属性是由哪个列怎么转化而来的.

  基本配置

    <!-- type定义了最终查询结果转化成了哪个类的对象 -->
    <resultMap id="studentResultMap" type="Student">
        <!-- mybatis创建对象的时候,调用构造方法需要传入的参数 -->
        <constructor>
            <idArg column="id" javaType="int"/>
        </constructor>
        <!-- 注入到对应对象的属性的列,property定义了对象的属性,column定义了对应的列 -->
        <result property="title" column="blog_title"/>
        <!-- 一个复杂的属性的注入,里面可以在定义一个resultMap, -->
        <association property="author" javaType="Author">
            <id property="id" column="author_id"/>
            <result property="username" column="author_username"/>
            <result property="password" column="author_password"/>
        </association>
        <!-- 一个集合类型,里面的属性可以是一个resultMap的list -->
        <collection property="posts" ofType="Post">
            <id property="id" column="post_id"/>
            <result property="subject" column="post_subject"/>
            <association property="author" javaType="Author"/>
            <!-- 根据查询结果,决定返回对象 -->
            <discriminator javaType="int" column="draft">
                <case value="1" resultType="DraftPost"/>
                <case value="2" resultType="Teatcher"/>
            </discriminator>
        </collection>
    </resultMap>
View Code

 

  加载过程

  resultMap是在MapperBuilder中加载的.在xml文件中配置的每一个<ResultMap>元素最后都会被加载成为一个ResultMap.resultMap元素中的每一个元素又都会被加载成一个ResultMapping.

  在ResultMapping中定义了一个数据库中查询结果的列是通过哪个typeHandler获取值,并且最后转化成了java的哪个类的实例.

  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    String type = resultMapNode.getStringAttribute("type",
        resultMapNode.getStringAttribute("ofType",
            resultMapNode.getStringAttribute("resultType",
                resultMapNode.getStringAttribute("javaType"))));
    Class<?> typeClass = resolveClass(type);
    if (typeClass == null) {
      typeClass = inheritEnclosingType(resultMapNode, enclosingType);
    }
    Discriminator discriminator = null;
    List<ResultMapping> resultMappings = new ArrayList<>(additionalResultMappings);
    List<XNode> resultChildren = resultMapNode.getChildren();
    for (XNode resultChild : resultChildren) {
      if ("constructor".equals(resultChild.getName())) {
        processConstructorElement(resultChild, typeClass, resultMappings);
      } else if ("discriminator".equals(resultChild.getName())) {
        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
      } else {
        List<ResultFlag> flags = new ArrayList<>();
        if ("id".equals(resultChild.getName())) {
          flags.add(ResultFlag.ID);
        }
        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
      }
    }
    String id = resultMapNode.getStringAttribute("id",
            resultMapNode.getValueBasedIdentifier());
    String extend = resultMapNode.getStringAttribute("extends");
    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
      return resultMapResolver.resolve();
    } catch (IncompleteElementException e) {
      configuration.addIncompleteResultMap(resultMapResolver);
      throw e;
    }
  }
View Code

  使用过程

  在mybatis执行完sql语句之后,就会调用DefaultResultHandler.handleResultSet(Statement)处理查询结果.

  在handleResultSet中,会通过Statement获取对应的resultMap.

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;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      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++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }
View Code

 

  使用handleRowValueForSimpleResultMap,遍历ResultSet,生成对应的对象.

  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
View Code

 

  通过getRowValue创建需要返回的对象,然后从当前的ResultSet获取值,放入生成的对象中.

  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    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;
  }
View Code

  通过getPropertyMappingValue从ResultMapping中获取列名,然后从resultset中获取值,然后从ResultMapping中获取响应的TypeHandler把查询出来的值转化成java中的类型,放入整体的返回结果中

  private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
      return DEFERRED;
    } else {
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      return typeHandler.getResult(rs, column);
    }
  }
View Code

 

 

 

 

 

 

 

 

 

  

标签:null,String,resultMap,resultMapNode,mybatis,原理,rsw,foundValues
From: https://www.cnblogs.com/monkeydai/p/16641505.html

相关文章

  • 数据结构之链表的原理
    链表:在计算机中用一组任意的存储单元存储线性表的数据元素称为链式存储结构,这组存储结构可以是连续的,也可以是不连续的,因此在存储数据元素时可以动态分配内存。注:在java中......
  • new的工作原理、new和字面量创建对象的区别
    new的工作原理:1.创建一个空对象,构造函数中的this会指向这个对象2.这个新对象会被链接到原型3.执行构造函数方法,其属性和方法都会被添加到this引用的对象中4.如果构造函......
  • MyBatis基础
    MyBatis是什么这里就引用一下,Mybatis官方文档的定义,来简单说明一下Mybatis的整体作用:MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis......
  • MyBatis常用注解及基本增删改查的注解实现
    MyBatis的常用注解注解可以减少Mapper文件的编写,常用注解如下;@Insert:实现新增@Update:实现更新@Delete:实现删除@Select:实现查询@Result:实现结果集封装@Results:可......
  • mybatis_13_SqlSessionFactory的DCL单例模式
    SqlSessionFactory的DCL单例模式 publicclassSqlSessionFactorySingleton{privateSqlSessionFactorySingleton(){}/***volatile关键字在此......
  • LinkedHashMap源码及LRU实现原理
    基本认识LinkedHashMap位于java.util包,于JDK1.4引入,属于JavaCollectionsFramework的成员。查看其UML关系如下图所示:HashMap在很多场景下都满足K-V的存取,而且在非多线......
  • Spring Boot注册Servlet、Filter、Listener原理
    如何使用在SpringBoot中注册Servlet、Filter办法主要有3种,下面来看下具体例子,例子都采用Filter,Servlet同理。第一种,使用FilterRegistrationBean、ServletRegistrationBe......
  • Synchronized的底层实现原理(看这篇就够了)
    谈到多线程就不得不谈到Synchronized,重要性不言而喻,今天主要分享Synchronized的底层实现。 Synchronizedsynchronized关键字解决的是多个线程之间访问资源的同步性,syn......
  • mybatis分页
    新人菜菜子再做项目之前没搞过分页 都是limit  上班了还这么搞 太土狗了项目上用了mybatis-plus百度了一下mybatis-plus怎么分页其他的配置项目之前都配置好了......
  • mybatis执行insert语句后,返回当前插入数据主键的方法 keyProperty区分大小写
    mybatis执行insert语句后,返回当前插入数据主键的方法keyProperty区分大小写#这样查询没有返回主键值<insertid="addLog"useGeneratedKeys="true"keyProperty="id"......