Mybatis源码(八)mybatis的查询的结果集的封装

前面的博客介绍执行的流程的增删改查,但是由于结果的集的封装我们没有讲清楚,所以写一篇博客。来详细的说明一下。mybatis的对查询的结果集的封装问题。前面的一篇博客介绍了mybatis会根据返回值类型,来决定执行什么样的操作。至此我们看下有那几种的返回的类型,然后写出对应的测试的方法。具体的代码如下:

public class MapperMethod {
	public static class MethodSignature {
	public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

可以看到返回的类型有类的类型,还有就是集合和数组的类型,然后就是游标的类型,Optional的类型,Map的类型。所以我们写出下面的测试的代码,具体如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="testResult.mapper.AdminMapper">
  <select id="selectByList" resultType="testResult.entity.Admin">
    select * from admin limit 3;
  </select>
  
  <select id="selectByMap" resultType="testResult.entity.Admin">
    select * from admin limit 3;
  </select>

  <select id="selectById" parameterType="int" resultType="testResult.entity.Admin">
    select * from admin where id = #{id};
  </select>

  <select id="selectByOption" resultType="testResult.entity.Admin">
    select * from admin where id = #{id};
  </select>

  <select id="selectByCursor" resultType="testResult.entity.Admin">
    select * from admin limit 3;
  </select>
</mapper>
package testResult.mapper;

import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.cursor.Cursor;
import testResult.entity.Admin;

import java.util.List;
import java.util.Map;
import java.util.Optional;

public interface AdminMapper {
  List<Admin> selectByList();
  
  @MapKey("id")
  Map<Long,Admin> selectByMap();
  
  Admin selectById(int id);

  Optional<Admin> selectByOption(int id);

  Cursor<Admin> selectByCursor();

}
package testResult.main;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import testResult.mapper.AdminMapper;

import java.io.IOException;
import java.io.InputStream;

public class TestResultMain {
  public static void main(String[] args) throws IOException {
    String resource = "mybatis.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sessionFactory.openSession();
    AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
    System.out.println(mapper.selectById(1));
    System.out.println(mapper.selectByOption(1));
    System.out.println(mapper.selectByList());
    System.out.println(mapper.selectByMap());
    System.out.println(mapper.selectByCursor());
    }
}

让我们开始我们的调试之旅,在调试之前,我们还是要了解一下resolvedReturnType的值,怎么计算出来的。具体的是调用resolveReturnType(method, mapperInterface)方法,我们跟进去看看,具体的代码如下:

public class TypeParameterResolver {
  public static Type resolveReturnType(Method method, Type srcType) {
    Type returnType = method.getGenericReturnType();
    Class<?> declaringClass = method.getDeclaringClass();
    return resolveType(returnType, srcType, declaringClass);
  }

  private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
    if (type instanceof TypeVariable) {
      return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
    } else if (type instanceof ParameterizedType) {
      return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
    } else if (type instanceof GenericArrayType) {
      return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
    } else {
      return type;
    }
  }
}

很明显这儿进过层层的调用最终返回的是testResult.entity.Admin,这个时候返回到最初调用的方法的地方,具体的代码如下:

public class MapperMethod {
	public static class MethodSignature {
	public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

上面走来的resolvedReturnType instanceof Class<?>判断是满足的,然后将returnType设置为testResult.entity.Admin,然后下面的return的属性都是为false。这个时候有了这些值后,我们就一步步的去看结果集是如何封装的。具体的代码如下:

public class MapperMethod {
	public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}

上面代码会调用sqlSession.selectOne(command.getName(), param);方法,具体的代码如下:

public class DefaultSqlSession implements SqlSession {
	@Override
  public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }
}

你会发现调用的还是selectList(statement, parameter);方法,这个方法我们之前讲过,所以这儿就不详细说。想了解详情的,可以看前面的博客。然后我们直接看具体的处理的结果集的方法。具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
		//创建一个新的List的集合。
    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);
  }
}

上面的方法就是入参是查询完成的PreparedStatement对象。这个总的方法我们需要好好看下。这个方法走来创建了一个空的list的集合,然后调用的getFirstResultSet(stmt);方法,这个方法返回一个 ResultSetWrapper对象。这是一个对结果集的包装对象,同时也将传入进来的ps对象传入到这个方法中去。具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    //获取结果集
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
      // move forward to get the first resultset in case the driver
      // doesn't return the resultset as the first result (HSQLDB 2.1)
      if (stmt.getMoreResults()) {
        rs = stmt.getResultSet();
      } else {
        if (stmt.getUpdateCount() == -1) {
          // no more results. Must be no resultset
          break;
        }
      }
    }
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }
}

上面的代码直接获取对应的结果集,然后由于是查询,这儿的结果集肯定不会空,于是会直接创建ResultSetWrapper对象,这个时候,我们需要跟进这个类的构造方法中去。具体的代码如下:

public class 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集合中去
      columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      //获取对应的jdbctype添加到jdbctypes集合中去
      jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
      //获取对应的列的类型添加到classNames集合中去
      classNames.add(metaData.getColumnClassName(i));
    }
  }
}  

上面的方法,最终将类型的转化器,列名,jdbctype,每列的类名包装起来。最后组成ResultSetWrapper返回,至此getFirstResultSet(stmt);方法就结束了。我们继续看原来的代码。

public class DefaultResultSetHandler implements ResultSetHandler {
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
		//创建一个新的List的集合。
    final List<Object> multipleResults = new ArrayList<>();
    int resultSetCount = 0;
    //一些重要的参数包装起来
    ResultSetWrapper rsw = getFirstResultSet(stmt);
		//获取resultMap,这个是之前在读取XML的时候封装好的
    List<ResultMap> resultMaps = mappedStatement.getResultMaps()
    int resultMapCount = resultMaps.size();//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);
  }
}

上面的代码经过一系列的调用,最终执行 handleResultSet(rsw, resultMap, multipleResults, null);方法,我们继续跟进去看看对应的代码,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      //传进来的值为null
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        //这个值默认为null
        if (resultHandler == null) {
          //创建默认的结果集处理类 其中包含一个默认的list集合
          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, defaultResultHandler, rowBounds, null);这个方法,我们继续跟进,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    //resultMap中只有一条,所以这个if不会进
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }
} 

上面的代码经过一系列调用,最终调用的是handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);方法,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	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()) {
      //解析有问题的map
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      //获取对应行的值
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
 } 

上面的代码重要的部分是获取对应行的值,调用getRowValue(rsw, discriminatedResultMap, null);方法,我们继续跟进对应的代码,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	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;
  }
} 

上面的代码会调用createResultObject(rsw, resultMap, lazyLoader, columnPrefix);创建对应的对象,我们继续跟进去,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    //构造参数的类型
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    //构造参数
    final List<Object> constructorArgs = new ArrayList<>();
    //创建结果集对象
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      //获取属性结果的映射
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
  }
} 

上面的代码经过一系列的调用,最终创建了结果集对象,只不过这个时候这个结果集对象没有对应的属性值,直接返回。我们继续看剩下的代码:

public class DefaultResultSetHandler implements ResultSetHandler {
	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())) {
      //根据结果集对象创建MetaObject对象
      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;
  }
} 

上面的代码会应用自动映射,这个时候会调用applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix)方法,我们继续跟进去,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    //创建对应列的类型的类型转换器的list
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    //判断不为空
    if (!autoMapping.isEmpty()) {
      //遍历进行赋值
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          //进行赋值
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }
} 

上面的方法就是进行对应的列中的值进行赋值,然后返回foundValues的值,只要赋值了这个值就为true,然后返回到原来的代码的地方。具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	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())) {
      //根据结果集对象创建MetaObject对象
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      //判断是否应该应用自动映射
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        //对返回的结果集进行对应的赋值,只要有赋值,就会返回true
        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;
  }
}

上面的代码执行完,然后执行applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix)方法,我们继续跟进对应的代码,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);//0
    boolean foundValues = false;
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();//0
    for (ResultMapping propertyMapping : propertyMappings) {
      String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      if (propertyMapping.getNestedResultMapId() != null) {
        // the user added a column attribute to a nested result map, ignore it
        column = null;
      }
      if (propertyMapping.isCompositeResult()
          || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
          || propertyMapping.getResultSet() != null) {
        Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
        // issue #541 make property optional
        final String property = propertyMapping.getProperty();
        if (property == null) {
          continue;
        } else if (value == DEFERRED) {
          foundValues = true;
          continue;
        }
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          metaObject.setValue(property, value);
        }
      }
    }
    return foundValues;
  }
}

取出来的长度都是0直接返回foundValues的值,foundValues的值为true,最后在返回到原来代码执行的地方

public class DefaultResultSetHandler implements ResultSetHandler {
	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())) {
      //根据结果集对象创建MetaObject对象
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      //判断是否应该应用自动映射
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      //返回的是true
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues; // true
      //直接将正确的结果集返回
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }
} 

上面的执行完成后,直接将封装好的对象直接返回,然后执行到如下的代码,具体如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	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()) {
      //解析有问题的map
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      //获取对应行的值
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
 } 

上面的代码最后会执行storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);我们继续跟进去,查看具体的代码,具体的代码如下:

private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
  if (parentMapping != null) {
    linkToParents(rs, parentMapping, rowValue);
  } else {
    callResultHandler(resultHandler, resultContext, rowValue);
  }
}
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
  resultContext.nextResultObject(rowValue);
  ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}

这个时候会将结果集添加到multipleResults集合中,最后我们再回到原来的代码的执行的地方,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      //传进来的值为null
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        //这个值默认为null
        if (resultHandler == null) {
          //创建默认的结果集处理类 其中包含一个默认的list集合
          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)
      //关闭rs
      closeResultSet(rsw.getResultSet());
    }
  }
}  

上面的代码就表示结果集封装完成。我们在回到原来执行的代码的地方,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
		//创建一个新的List的集合。
    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);
  }
}

上面的循环会遍历所有的结果,一条条的封装,由于我们只返回一条数据,所以这个循环就结束了。最后将对应的结果集进行返回就行了,至此整个单条记录的封装就结束了。

我们继续看封装成Optional对象的,至此我们会讲述不同的地方,相同的就直接略过。这个时候走来不一样的就是返回值的类型不一样,这个时候返回的类型就是参数化类型,参数化类型简单的说就是泛性。这个时候看下如下的代码

public class MapperMethod {
	public static class MethodSignature {
	public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {//参数化类型可以理解成泛性
        //获取对应的原始类型(非泛性)
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

上面代码由于是返回的是optional的类型的参数,所以这儿的returnType的值为optional,然后returnsOptional的值为true,然后其他为false,同时对象为null。我们继续跟进相应的代码。

public class MapperMethod {
	public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}

这个你会发现查询单条的原理是一样的,唯一不同的在最后有了一个判断,判断是不是optional类,还有就是result的值为空,或者返回的类型不是optional类型,前面的条件满足就将结果封装成optional对象。返回的结果是optional对象就讲完了。

接下来我们看查询的返回值是list的情况。具体的代码如下:

public class MapperMethod {
	public static class MethodSignature {
	public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {//参数化类型可以理解成泛性
        //获取对应的原始类型(非泛性)
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

这个时候returnType的值是list,然后returnsMany的值为true,其他的都是一样的。然后我们看执行的逻辑,具体的代码如下:

public class MapperMethod {
	public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}

这个时候会执行executeForMany(sqlSession, args);方法。最终逻辑还是一样的,需要注意的是,以下的循环会执行多次,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
	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()) {
      //解析有问题的map
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      //获取对应行的值
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
 } 

这儿会将查出来的东西,全部遍历封装到指定的对象中去。最后添加到defaultResultHandler中去,然后返回,最后存入multipleResults集合中去。最后将这个集合进行返回。至此返回list的集合执行完成。

接下来看的就会死返回的是map的类型,我们继续看如下的代码

public class MapperMethod {
	public static class MethodSignature {
	public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {//参数化类型可以理解成泛性
        //获取对应的原始类型(非泛性)
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
    	//这个时候获取的mapKey为id,我加了对应的注解
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

这个时候returnType 的值为Map,然后mapKeyid,然后returnsMap的值为true,我们继续跟进对应的代码,具体的代码如下:

public class MapperMethod {
	public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}

这个时候上面会执行executeForMap(sqlSession, args);方法。我们继续跟进去对应的代码,具体的代码如下:

public class MapperMethod {
  private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
    Map<K, V> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds);
    } else {
      result = sqlSession.selectMap(command.getName(), param, method.getMapKey());
    }
    return result;
  }
} 

因为没有分页,所以这儿会执行的else中查询Map的的方法, sqlSession.selectMap(command.getName(), param, method.getMapKey());我们继续跟进对应的代码,具体的代码如下:

public class DefaultSqlSession implements SqlSession {
  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
    final List<? extends V> list = selectList(statement, parameter, rowBounds);
    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
            configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    final DefaultResultContext<V> context = new DefaultResultContext<>();
    for (V o : list) {
      context.nextResultObject(o);
      mapResultHandler.handleResult(context);
    }
    return mapResultHandler.getMappedResults();
  }
}  

上面调用selectList(statement, parameter, rowBounds);方法就是我们之前看的查询的方法,然后创建两个对象。然后遍历这个list,我们现在要的看的方法就是context.nextResultObject(o);具体的代码如下:

public class DefaultResultContext<T> implements ResultContext<T> {
	public void nextResultObject(T resultObject) {
    resultCount++;
    this.resultObject = resultObject;
  }
} 

取出对应的值包装到DefaultResultContext对象中去,然后将resultCount++;,这个时候我们需要看的是mapResultHandler.handleResult(context);具体的代码如下:

public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {
  @Override
  public void handleResult(ResultContext<? extends V> context) {
    //取出刚才包装的对象
    final V value = context.getResultObject();
    //获取对应的元数据
    final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
    // TODO is that assignment always true?
    //根据对应mapKey取出对象的值
    final K key = (K) mo.getValue(mapKey);
    //放入对应的Map集合中去
    mappedResults.put(key, value);
  }
}  

走来取出刚才的包装的对象,然后取出对应mapKey在对象中值作为键,然后添加到mappedResultsmap中去。最终进行返回。至此包装Map就讲完了。

最后我们再来讲下返回的类型是游标的类型,具体的代码如下:

public class MapperMethod {
	public static class MethodSignature {
		public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {//参数化类型可以理解成泛性
        //获取对应的原始类型(非泛性)
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      //返回的类型是Cursor对象
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
    	this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
	}
}

这个时候returnType的类型是Cursor类型,然后returnsCursortrue,我们继续看查询的代码,具体如下:

public class MapperMethod {
	public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}

这个时候由于返回的结果是游标的类型,所以这儿会执行executeForCursor(sqlSession, args);这个方法,具体的代码如下:

public class MapperMethod {
	private <T> Cursor<T> executeForCursor(SqlSession sqlSession, Object[] args) {
    Cursor<T> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.selectCursor(command.getName(), param, rowBounds);
    } else {
      result = sqlSession.selectCursor(command.getName(), param);
    }
    return result;
  }
}  

由于这儿没有分页,所以会直接执行sqlSession.selectCursor(command.getName(), param);具体的代码如下:

public class DefaultSqlSession implements SqlSession {
  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    return selectCursor(statement, parameter, RowBounds.DEFAULT);
  }
  
  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
      registerCursor(cursor);
      return cursor;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
}

然后会调用executor.queryCursor(ms, wrapCollection(parameter), rowBounds);方法,具体的代码如下:

public class CachingExecutor implements Executor {
  @Override
  public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.queryCursor(ms, parameter, rowBounds);
  }
}

然后会调用delegate.queryCursor(ms, parameter, rowBounds);具体的代码如下:

public class SimpleExecutor extends BaseExecutor {
  @Override
  protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    stmt.closeOnCompletion();
    return handler.queryCursor(stmt);
  }
}

这个时候会执行 handler.queryCursor(stmt);方法,具体的代码如下:

public class RoutingStatementHandler implements StatementHandler {
  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    return delegate.queryCursor(statement);
  }
}

public class PreparedStatementHandler extends BaseStatementHandler {
  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleCursorResultSets(ps);
  }
}

上面的代码会执行resultSetHandler.handleCursorResultSets(ps);我们继续跟进对应的代码,具体的代码如下:

public class DefaultResultSetHandler implements ResultSetHandler {
  @Override
  public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());

    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();

    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    if (resultMapCount != 1) {
      throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
    }

    ResultMap resultMap = resultMaps.get(0);
    return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
  }
}  

上面的代码和前面的代码是如此的相似,这儿直接略过了。然后创建DefaultCursor对象,我们直接跟进去,具体的代码如下:

public class DefaultCursor<T> implements Cursor<T> {
	public DefaultCursor(DefaultResultSetHandler resultSetHandler, ResultMap resultMap, ResultSetWrapper rsw, RowBounds rowBounds) {
    this.resultSetHandler = resultSetHandler;
    this.resultMap = resultMap;
    this.rsw = rsw;
    this.rowBounds = rowBounds;
  }
}

这个时候就创建好了DefaultCursor的游标对象,然后直接返回。最后直接执行registerCursor方法,具体的代码如下:

public class DefaultSqlSession implements SqlSession {
	private <T> void registerCursor(Cursor<T> cursor) {
    if (cursorList == null) {
      cursorList = new ArrayList<>();
    }
    cursorList.add(cursor);
  }
}

至此整个结果集的封装已经讲完了。下篇博客会讲下mybatis的一些面试题。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值