• 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

  • 相关阅读:
    网站安全防护措施
    2024年保安员职业资格考试真题分享
    [Machine Learning][Day1]监督学习和无监督学习
    113.Impala ODBC驱动的安装及配置
    IOS逆向初探
    java8 lambda常用方法汇总
    文件批量重命名 Renamer 最新中文 for mac
    业务数据分析-Excel公式与函数(三)
    Kafka RecordAccumulator 二
    WPF中的DataContext
  • 原文地址:https://blog.csdn.net/lk2015/article/details/126939907