• mybatis查询所得list集合,get(0)对象为null问题


    问题场景:

    代码中获取mybatis查询返回的list集合,获取第一个对象,get方法获取属性值
    在这里插入图片描述


    问题描述

    在上述场景下,获取属性值时报出空指针错误
    photoInfo.getValidEndDate()
    在这里插入图片描述


    原因分析:

    源头是查询的sql有问题,原先查询的表中新增了字段,sql查询的数据为本次新增字段,查询结果中所有字段值皆为null。mybatis转换结果集时将null存入List返回,get(0)获取首个存储对象,实际获取为null,导致获取属性值时报出空指针。给新增字段赋值或者查询sql中添加查询一个必有值的字段,解决报错。


    部分mybatis源码:

    ResultSetHandler是Mybatis的核心组件,将结果集resultSets转化成结果列表(或cursor)和处理储存过程的输出。
    DefaultResultSetHandler是Myabtis为ResultSetHandler提供的唯一一个实现类,查看DefaultResultSetHandler的源码了解结果集resultSet的过程。

    类DefaultResultSetHandler >> 方法handleResultSets() >> 方法handleRowValues() >> 方法handleRowValuesForSimpleResultMap() >> 方法getRowValue()
    最终getRowValue()返回了null,因此获取mybatis查询的list,get(0)也获取了null导致获取属性报错。

      @Override
      public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
        //返回的list集合
        final List<Object> multipleResults = new ArrayList<Object>();
    
        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);
          //处理rsw生成java对象
          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);
      }
    
      @SuppressWarnings("unchecked")
      private List<Object> collapseSingleResultList(List<Object> multipleResults) {
        return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : 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) {
              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());
        }
    
    
      //
      // HANDLE ROWS FOR SIMPLE RESULTMAP
      //
    //处理行数据
      public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        if (resultMap.hasNestedResultMaps()) {
          ensureNoRowBounds();
          checkResultHandler();
          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);
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
          ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
          //获取返回对象
          Object rowValue = getRowValue(rsw, discriminatedResultMap);
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }
    
     //
      // GET VALUE FROM ROW FOR SIMPLE RESULT MAP
      //
    
      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())) {
          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;
          //这一步返回了null,returnInstanceForEmptyRow 该配置决定字段全为null是否返回null还是对象,默认false
          rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
        }
        return rowValue;
      }
      
    

    源码分析参考:https://blog.csdn.net/qq_33762302/article/details/115340060

  • 相关阅读:
    【软考:系统集成项目管理】之 项目采购管理
    Unity Xlua热更新框架(三):资源管理
    关于pytorch损失函数的梯度计算
    python-多线程创建以及查看
    SSM+优秀宿舍评选系统 毕业设计-附源码221511
    MySQL命令行插入数据乱码分析
    网络传输: 序列化与反序列化
    北漂七年拿过阿里、腾讯、华为offer的资深架构师,分享经验总结
    MATLAB未定义函数或变量‘polyadd‘的解决办法
    form组件的封装(element ui ) 简单版本
  • 原文地址:https://blog.csdn.net/lk2015/article/details/126939907