`

MyBatis原理(2)-执行流程 3 处理结果集

 
阅读更多
DefaultResultSetHandler#handleResultSets 处理结果集

@Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
   //获取第一个结果集,屏蔽数据库驱动造成的不同,
  //ResultSetWrapper是对ResultSet元数据的封装
    ResultSetWrapper rsw = getFirstResultSet(stmt);
   //获取返回类型-resultType会被转换为Inline的ResultMap(id变为namespace+“Inline” see MapperBuilderAssistant#getStatementResultMaps)
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
  //如果结果集不为空,resultMapCount<1抛出异常
    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);
  }
//处理当前结果集
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {
           //结果处理器为空resultHandler从构造Executor传入
          //构造默认的结果处理器,使用objectFactory创建结果集
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          //处理当前ResultMap中每一行 
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          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 {
   //如果有嵌套的(子句中包含select属性)
    if (resultMap.hasNestedResultMaps()) {
     //确保字句中没有分页
      ensureNoRowBounds();
    //确保子句中没有ResultHandler
      checkResultHandler();
    //处理嵌套的ResultMap
      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<Object>();
    //跳过指定偏移量---分页
    skipRows(rsw.getResultSet(), rowBounds);
    //context中结果条数小于rowBounds的limit获取结果集下一个
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
     //首先循环处理嵌套鉴别器,将解析后的最后一个resultMap作为当前resultMap,无鉴别器则返回当前resultMap
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
       //获取当前行的值
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      //如过parentMapping不为空,将rowvalue设置给parent,否则回调自己的ResultHandler
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }


 private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
     //ResultLoaderMap存储了LoadPair的hashMap,对应一个对象,每一个LoadPair则对应
   //对象的每一个属性和其延迟加载器 ResultLoader,ResultLoader封装了executor,parameterObject,objectFactory,cacheKey等必要的一切属性用来再次执行sql(包括当前线程和其他线程)
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  //初始化返回对象,如过有嵌套查询则创建lazyLoader的代理对象,并返回
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
    // 给rowvalue设置值
    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, null) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }

分享到:
评论

相关推荐

    Mybatis常见知识点.md

    - Mybatis SQL执行流程 - Executor的类型 - 什么是延迟加载? - 延迟加载原理 - ${} 和 #{}的区别 - Mybatis 模糊查询LIKE怎么写 - Mybatis是如何获取生成的主键的? - Mybatis动态SQL是什么? - Mybatis插件...

    mybatis-r2dbc:MyBatis R2DBC适配器

    Reactive框架为R2DBC提供了执行调度功能结果处理和映射: 支持,你也可以扩展R2DBCTypeHandler添加自定义类型。MyBatis R2DBC增加了JDBC Types的支持,主要是考虑兼容性。如何使用?和MyBatis的使用流程一样,如下:/...

    mybatis原理.xmind

    该思维导图主要是对MyBatis原理知识进行了整理,通过对底层的分析,能够实现手写一个实现核心功能的简单MyBats,内容包括MyBatis整体架构和流程的分析、SQL的解析过程、手写解析流程、手写执行流程、看源码、MyBatis...

    SSM框架原理 spring-mvc执行流程

    分类专栏: java框架 文章标签: spring mvc spring mybatis 作用: SSM框架是spring MVC ,... springMVC执行流程: 1. 客户端将请求统一提交到DispatcherServlet; 2. DispatcherServlet会将请求交给HandlerMapping

    mybatis源码流程解析,找工作好帮手

    自己阅读源码及查询资料所写的mybatis源码总结, 包含了mybatis一级缓存、二级缓存,及缓存中常遇到的缓存击穿、缓存雪崩、缓存穿透...挖掘mybatis从配置文件、接口到如何执行sql深层原理;常用的关联查询、嵌套查询等

    基于jbpm与activiti的工作流平台技术架构介绍

    BPMX3是支持流程管理、监控、优化、再造的全套IT管理开发平台,并且集单点登录、企业单位门户、业务流程管理、开发、整合、业务分析及重构等多重职能于一身的软件开发工具和企业IT架构平台。 BPMX3是企业管理业务...

    动力节点SSM课件源码分析教程配套资料分享

    提高核心竞争力,那么本套视频课程带你深入理解MyBatis、Spring及SpringMVC框架执行流程、底层原理、实现源码,让你对经典流行开源框架做到知其然亦知其所以然,让知识真正地学以致用。 其中有大量一线大厂高频面试...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题48.struts2的执行流程或者struts2的原理.mp4 │ Java面试题49.Struts2的拦截器是什么?你都用它干什么?.mp4 │ Java面试题50.Spring MVC的执行流程.mp4 │ Java面试题51.SpringMVC和Struts2的不同.mp4...

    Spring.3.x企业应用开发实战(完整版).part2

     《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练...

    Spring3.x企业应用开发实战(完整版) part1

     《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练...

    Java常见面试题208道.docx

    面试题包括以下十九部分:Java 基础、容器、多线程、反射、对象拷贝、Java Web 模块、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql...

    基于SpringBoot的公司协同办公平台的设计与实现

    再次,分析了系统总体建设范围,通过用例图、流程图等 UML 建模方式,描述了用户可以执行的功能和业务处理机制,并对软件架构、UI 界面、安全等方面的非功能性需求进行分析。同时,构建了系统体系结构、技术架构与...

    涵盖了90%以上的面试题

    hashmap的底层原理 hashmap产生死锁的原因 hashmap的容量为什么一定要是2的幂呢 TreeMap的底层原理 HashMap,Hashtable和ConcurrentHashMap的区别 在ArrayList和LinkedList尾部添加元素,谁的效率更高 如果HashMap或者...

    Java-CS-Record:记录准备春招实习过程中,学习与复习的知识(模块化整理,非面试题速成)。注:已拿阿里 offer,暂停更新!

    Java-CS-Record这是一个频繁更新的项目(2020.9 ~ 2021.3)。文章说明这个仓库的文章,都是...目录基础1、Java 核心常见特性源码类型相关特性相关 反射相关问题与源码解析注解底层源码解析 Stream 执行流程源码解析 S

    idea使用教程2017-06-01.pdf

    Build Execution Deployment(构建执行部署)............................................................ 48 Languages&Frameworks.............................................................................

    JAVA核心知识点整理(有效)

    25 3:ServicorTo 和 ServicorFrom 互换................................................................................................................25 2.3.3.1. 2.4.1. 如何确定垃圾 ......................

Global site tag (gtag.js) - Google Analytics