Mybatis底层原理学习(三):查询结果集的处理原理

【福利】关注微信公众号:深夜程猿,回复关键字即可获取学习视频、简历模版

Mybatis支持多结果集,也就是结果集中的元素也可以是结果集,返回结果集的时候会调用相应的结果集处理器来处理结果集。我们来从源码角度看看具体的实现原理

首先,在查询操作,执行sql语句返回查询结果集后,调用默认的结果集处理器handleResultSets方法

DefaultResultSetHandler#handleResultSets
 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;
    //  获取第一个结果集,如果没有结果集,那么返回null
    // 获取第一个结果集在于知道sql语句要操作到哪些元素数据(表的列),会获取到元数据名称、Java数据类型、JDBC数据类型
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    // 获取执行的sql配置的resultMap
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    // 一个resultMap对应一个结果集,依次遍历resultMap并处理结果集
    while (rsw != null && resultMapCount > resultSetCount) {// 从条件可以看出,结果集个数和resultMap数量一样
      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);
  }
复制代码

我们看一下是怎么获取第一个结果集的

DefaultResultSetHandler#getFirstResultSet
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
       // 没有结果集,也许是数据库驱动还没有返回第一个结果集
      if (stmt.getMoreResults()) {
        // 尝试再一次获取结果集
        rs = stmt.getResultSet();
      } else {
        if (stmt.getUpdateCount() == -1) {
          //rs == null && stmt.getUpdateCount() == -1表示驱动已经返回,没有更多结果,没有结果集
          break;
        }
      }
    }
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }
复制代码
ResultSetWrapper#构造函数
// 封装结果集
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
    super();
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.resultSet = rs;
    final ResultSetMetaData metaData = rs.getMetaData();
    final int columnCount = metaData.getColumnCount();  
    // 设置结果集的元数据
    for (int i = 1; i <= columnCount; i++) {
      columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
      classNames.add(metaData.getColumnClassName(i));
    }
  }
复制代码

我们继续看下handleResultSet(rsw, resultMap, multipleResults, null);的具体实现

DefaultResultSetHandler #handleResultSet
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) { 
        // 没有自定义结果集处理器,使用默认的结果集处理器处理结果集
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          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());
    }
  }
复制代码

接着看handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);的实现

DefaultResultSetHandler#handleRowValues
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) { // 判断resultMap是否有嵌套的resultMap
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }
复制代码

先看下没有嵌套resultMap的处理逻辑handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);

DefaultResultSetHandler#handleRowValuesForSimpleResultMap
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);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      // 处理行数据,并封装成指定的resultType
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      // 缓存对象,修改rowBounds的值
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }
复制代码

再往下分析怎么获取行数据并封装成指定的resultType

DefaultResultSetHandler#getRowValue
// 获取行数据值
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
    // 行数据对象不是null,并且没有结果类型处理器
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      }
      // 应用resultMap的属性映射配置,为行数据对象设置从数据库获取回来的值
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
    }
    // 返回处理过的行数据对象
    return rowValue;
  }
复制代码

简单分析了结果集的处理原理,它基本步骤:

  • 解析SQL语句
  • 执行SQL语句
  • 根据SQL映射配置,比如resultMap或者resulType,resultSets等来对步骤2获取回来的结果集处理
  • 返回处理过的结果集
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值