MyBatis运行原理(三) : 多参数封装Map的流程、查询实现原理 (源码分析)

四、MyBatis多个参数封装Map的过程

1、首先在该处打上断点
在这里插入图片描述
在这里插入图片描述
因为mapper是代理对象, 进入代理类MapperProxy中的invoke方法

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
    // 判断是否是Object中的方法, method对象就是上面的getUser方法
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 主要进入该方法中
    return mapperMethod.execute(sqlSession, args);
  }

进入到MapperMethod类的execute方法, 因为是查询方法, 所以仅为SELECT分支

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);
    // 这里可以发现, 底层仍然使用的是selectOne方法
    result = sqlSession.selectOne(command.getName(), param);
    if (method.returnsOptional()
        && (result == null || !method.getReturnType().equals(result.getClass()))) {
      result = Optional.ofNullable(result);
    }
  }
  break;

进入convetArgsToSqlCommandParam方法的ParamNameResolver类的getNamedParams方法


在下面代码之前, 要搞懂ParamNameResolver类中private final SortedMap<Integer, String> names;的值是怎么来的. 是在ParamNameResolver构造器中初始化的

public ParamNameResolver(Configuration config, Method method) {
	// 获取getUser方法的参数类型
  final Class<?>[] paramTypes = method.getParameterTypes();
  // 获取getUser方法的注解
  final Annotation[][] paramAnnotations = method.getParameterAnnotations();
  final SortedMap<Integer, String> map = new TreeMap<>();
  int paramCount = paramAnnotations.length;
  // get names from @Param annotations
  for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
    if (isSpecialParameter(paramTypes[paramIndex])) {
      // skip special parameters
      continue;
    }
    String name = null;
    for (Annotation annotation : paramAnnotations[paramIndex]) {
    	// 用来判断方法参数是否标注了@Param注解, 如果2个参数都标注了
    	// 会封装为 {0=id, 1=name}
      if (annotation instanceof Param) {
        hasParamAnnotation = true;
        name = ((Param) annotation).value();
        break;
      }
    }
    if (name == null) {
      if (config.isUseActualParamName()) {
        name = getActualParamName(method, paramIndex);
      }
      if (name == null) {
        // 如果没有标注param注解, 封装的map为 {0=arg0)
        name = String.valueOf(map.size());
      }
    }
    map.put(paramIndex, name);
  }
  // 因为2个参数都标注了@Param注解, 所以names={0=id, 1=name}
  names = Collections.unmodifiableSortedMap(map);
}

下面就是核心代码: 为什么添加了@Param的参数会封装为Map, 为什么#{param1}…可以成功

	// args数组里面的值为: [12, "lisi"]
  public Object getNamedParams(Object[] args) {
    final int paramCount = names.size(); // 此时names就为{0=id, 1=name}
    if (args == null || paramCount == 0) {
      return null;
      // 如果方法只有一个参数&&该参数没有标注@Param注解, 直接返回该值
    } else if (!hasParamAnnotation && paramCount == 1) {
      // 此时只有一个参数, 根本不会封装为下面的ParamMap
      return args[names.firstKey()]; // 返回的是args[0] --> 12
    } else {
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        // 循环后: param这个map中存放的就是: 
        // {id=args[0], name=args[1]}-->{id=12, name="lisi"}
        // 所以说@Param标注的参数, 底层仍然使用的是Map的方式, 采用#{key}来取值即可
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        // 下面的常量就是:param字符串
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
		  // 除了会存放上面的, param中还存放了{param1=12, param2="lisi"}
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      // {name=lisi, id=12, param1=12, param2=lisi}
      // 如此一来我们就可以#{key}或者#{param1}...#{paramN}的方式来取值了
      return param;
    }
  }

在这里插入图片描述

五、查询实现原理

在这里插入图片描述
1、因为mapper是一个代理对象, 实现了InvocationHandler, 所以在执行目标方法之前要执行invoke方法, 所以进入到Invoke方法

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // 判断当前方法是不是Object中声明的方法
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    // method: public abstract com.sunny.domain.User com.sunny.mapper.UserMapper.getUserById(int)
    // 将method包装为mybatis能识别的MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 执行execute: args为传过来的参数12
    return mapperMethod.execute(sqlSession, args);
  }

2、进入MapperMethod的execute方法, 根据SQL语句, 选择SELECT分支

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 {
          // 这个将参数转换为sql命令参数的方法, 在后面会专门分析,多个参数转map的过程
          // 如果args为一个参数直接返回, 多个参数泽包装为一个map的过程
          Object param = method.convertArgsToSqlCommandParam(args);
          // 下面进入该方法, SqlCommand封装了SQL语句的信息
          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;
  }

3、进入的DefaultSqlSession的selectOne方法

@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;
  }
}

@Override
public <E> List<E> selectList(String statement, Object parameter) {
  return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      // 通过configuration获取MappedStatement, 因为ms封装了CRUD标签的详细信息
      // 并且包含了sqlSource的信息(如下图)
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 执行executor的查询方法
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

// 在executor.query之前, 先判断传进来的参数是否是Collection类型
// 下面的逻辑就标明了, 在编写mapper.xml中 List --> #{list}; Array --> #{array}的取值方式
private Object wrapCollection(final Object object) {
  if (object instanceof Collection) {
    StrictMap<Object> map = new StrictMap<>();
    map.put("collection", object);
    if (object instanceof List) {
      map.put("list", object);
    }
    return map;
  } else if (object != null && object.getClass().isArray()) {
    StrictMap<Object> map = new StrictMap<>();
    map.put("array", object);
    return map;
  }
  return object;
}

在这里插入图片描述

4、进入的CachingExecutor的query方法

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  // 获取到sql语句的详细信息
  // BoundSql: SQL绑定, 封装SQL语句和对应的参数信息。
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

BoundSql内容
在这里插入图片描述
5、再进入上面return query方法

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  // 判断是否有二级缓存
  Cache cache = ms.getCache();
  if (cache != null) {
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
      ensureNoOutParams(ms, boundSql);
      @SuppressWarnings("unchecked")
      List<E> list = (List<E>) tcm.getObject(cache, key);
      if (list == null) {
        list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578 and #116
      }
      return list;
    }
  }
  // 此时的delete就是你全局配置的那个执行器,这里没有配置默认为: SimpleExecutor
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

6、进入BaseExecutor的query方法

@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  if (queryStack == 0 && ms.isFlushCacheRequired()) {
    clearLocalCache();
  }
  List<E> list;
  try {
    queryStack++;
    // 从一级缓存中拿, 这也印证了先从二级缓存拿, 然后再一级缓存
    list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
    if (list != null) {
      handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else {
      // 没有缓存, 则从该方法中查询数据
      list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
  } finally {
    queryStack--;
  }
  if (queryStack == 0) {
    for (DeferredLoad deferredLoad : deferredLoads) {
      deferredLoad.load();
    }
    // issue #601
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      // issue #482
      clearLocalCache();
    }
  }
  return list;
}

7、进入到queryFromDatabase方法

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    // 往一级缓存存放数据, value为占位符
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    // 当查询出数据后, 再将查出的数据作为value存放到map
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

在这里插入图片描述
8、进入到BaseExecutor的doQuery方法, 走的是子类SimpleExecutor的doQuery方法

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    // 原生JDBC的Statement
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // 创建了StatementHandler对象: 这里为PreparedStatementHandler对象
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 下面进入到RoutingStatementHandler来判断创建的StatementHandler
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 创建的statementHandler类型为PreparedStatementHandler,
    // 会经过拦截器链进行包装增强(类似aop的功能)
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }


  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

	// 从MeppedStatement中获取StatementType的类型
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        // 如果没有设置, 默认为PREPARED预编译的方式
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
  }

// 可以在crud标签中设置, 默认为PREPARED预编译的方式  
public enum StatementType {
  STATEMENT, PREPARED, CALLABLE
}
// 在创建PreparedStatementHandler对象的时候, 使用super调用父类的构造器, 
// 同时也将parameterHandler, resultSetHandler也创建了: 下面会使用到这俩对象
  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

// PreparedStatementHandler父类BaseStatementHandler的构造器
  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

	// 创建下面俩对象之后, 仍然会经过拦截器链进行包装增强然后返回对象(类似aop的功能)
   // statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

9、返回到SimpleExecutor类doQuery方法, 并进入prepareStatement方法

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  Connection connection = getConnection(statementLog);
  // 拿到一个连接, 进行参数预编译设置到stmt中, handler:PrepareStatementHandler
  stmt = handler.prepare(connection, transaction.getTimeout());
  // 进行参数预编译
  handler.parameterize(stmt);
  return stmt;
}

在这里插入图片描述

10、进入到 PreparedStatementHandler的parameterize方法: 进行参数预编译

  @Override
  public void parameterize(Statement statement) throws SQLException {
    // 会调用parameterHandler设置参数
    parameterHandler.setParameters((PreparedStatement) statement);
  }

11、进入DefaultParameterHandler的setParameters方法

@Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value; // 12
          // "id"
          String propertyName = parameterMapping.getProperty();
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            // 调用的是TypeHandler给SQL预编译设置参数
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

12、进入到typeHandler.setParameter(ps, i + 1, value, jdbcType)方法

  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
              + "Cause: " + e, e);
      }
    } else {
      try {
        // 设置非空预编译参数
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different configuration property. "
              + "Cause: " + e, e);
      }
    }
  }

13、进入到UnknownTypeHandler类的setNonNullParameter(ps, i, parameter, jdbcType)方法

// 进入到setNonNullParameter(ps, i, parameter, jdbcType)方法
  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
      throws SQLException {
    TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
    // 此时会进入IntegerTypeHandler的方法
    handler.setParameter(ps, i, parameter, jdbcType); 
  }

// 根据传过来的parameter的类型, 创建该类型的handler, 此处为: IntgerTypeHandler
  private TypeHandler<?> resolveTypeHandler(Object parameter, JdbcType jdbcType) {
    TypeHandler<?> handler;
    if (parameter == null) {
      handler = OBJECT_TYPE_HANDLER;
    } else {
      handler = typeHandlerRegistry.getTypeHandler(parameter.getClass(), jdbcType);
      // check if handler is null (issue #270)
      if (handler == null || handler instanceof UnknownTypeHandler) {
        handler = OBJECT_TYPE_HANDLER;
      }
    }
    return handler;
  }

14、再次进入setParameter方法

  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
              + "Cause: " + e, e);
      }
    } else {
      try {
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different configuration property. "
              + "Cause: " + e, e);
      }
    }
  }

// 此时进IntegerTypeHandler的setNonNullParameter方法
// 第一次进入的是UnknownTypeHandler的setNonNullParameter方法
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
      throws SQLException {
    // 给预编译参数设置值(最终设置)
    ps.setInt(i, parameter);
  }

15、此时返回到BaseTypeHandler之后, 执行完setNonNullParameter方法后, 就成功给预编译sql设置上了值
在这里插入图片描述

16、层层向上返回到SimpleExecutor的doQuery方法的return handler.query(stmt, resultHandler); 来执行具体的查询操作, 封装结果集操作

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    // 执行 com.mysql.jdbc.JDBC42PreparedStatement@79c97cb: 
    // SELECT * FROM user WHERE id = 12 该SQL的查询操作
    ps.execute();
    // 根据查询出来的数据, 封装结果集(赋值到JavaBean对象中)
    return resultSetHandler.handleResultSets(ps);
  }

17、进入到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<>();

    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++;
    }

18、进入到handleResultSet方法, 再进入handleRowValues方法, 再进入handleRowValuesForSimpleResultMap方法, 再进入getRowValue方法, 再进入applyAutomaticMappings方法

  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    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;
  }

19、在设置上面metaObject.setValue之前, 要进行数据库列类型和JavaBean类型做映射。

  private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
      return DEFERRED;
    } else {
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      // 同样采用typeHandler来处理参数映射
      return typeHandler.getResult(rs, column);
    }
  }

// IntegerTypeHandler中的getNullableResult来获取columnName列的值
  @Override
  public Integer getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    int result = rs.getInt(columnName);
    return result == 0 && rs.wasNull() ? null : result;
  }

// 其他字段同理这样获取, 只是采用的TypeHandler不同, 然后都通过
// metaObject.setValue(mapping.property, value);设置给metaObject

在这里插入图片描述

最终取出数据设置给JavaBean对象
在这里插入图片描述

20、最后将查询到的数据赋值给JavaBean对象
在这里插入图片描述
在这里插入图片描述

查询流程总结:
在这里插入图片描述
在这里插入图片描述

1、获取sqlSessionFactory对象:
		解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;
		注意:【MappedStatement】:代表一个增删改查的详细信息

2、获取sqlSession对象
		返回一个DefaultSQlSession对象,包含Executor和Configuration;
		这一步会创建Executor对象;

3、获取接口的代理对象(MapperProxy)
		getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象
		代理对象里面包含了,DefaultSqlSession(Executor)
4、执行增删改查方法

总结:
	1、根据配置文件(全局,sql映射)初始化出Configuration对象
	2、创建一个DefaultSqlSession对象,
		他里面包含Configuration以及
		Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
 3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy;
 4、MapperProxy里面有(DefaultSqlSession);
 5、执行增删改查方法:
 		1)、调用DefaultSqlSession的增删改查(Executor);
 		2)、会创建一个StatementHandler对象。
 			(同时也会创建出ParameterHandler和ResultSetHandler)
 		3)、调用StatementHandler预编译参数以及设置参数值;
 			使用ParameterHandler来给sql设置参数
 		4)、调用StatementHandler的增删改查方法;
 		5)、ResultSetHandler封装结果
 注意:
 	四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white camel

感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值