第八篇:SqlSession.selectList调用过程

之所以要说这个,是因为其他方法都跟这个差不多,而且这个才涉及到参数的填充过程等,这个过程你看懂了,其他的方法就难不倒你了,先看下基本的代码编写

样例

//工厂工具类
public class FactoryUtils {
    public static SqlSessionFactory sqlSessionFactory() {
        return sqlSessionFactory(null);
    }

    public static SqlSessionFactory sqlSessionFactory(Properties properties) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new SqlSessionFactoryBuilder().build(inputStream, properties);
    }
}


//sql执行测试类

public class SqlSessionTest {

    public static void main(String[] args) throws Exception{

        //获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = FactoryUtils.sqlSessionFactory();

        //打开SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行sql语句
        List<User> userList = sqlSession.selectList("com.zxc.study.test.mapper.UserMapper.selectUser", 1);
        //操作返回结构
        System.out.println(userList);
    }
}

源码入口之sqlSession.selectList

org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)


RowBounds 默认为 RowBounds.DEFAUL
ResultHandler 默认为 NULL


  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //从配置中获取MappedStatement对象,其实就是一个map,key就是statement组装的
      MappedStatement ms = configuration.getMappedStatement(statement);
      //使用executor对象执行查询逻辑
      //wrapCollection包装参数,有可能传进来的是集合
      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();
    }
  }



第一步就是从一个map中获取 MappedStatement 对象,没什么好看的
第二步才是核心的操作过程

至于 wrapCollection只是判断了一下参数是Collection或者是Array进行了一层包装

Executor(CachingExecutor).query

首先会先到 org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)中


  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //获取绑定sql对象
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    //主要是为了缓存设计的对象
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    //执行查询数据库操作
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }



这里面设置了两个逻辑

1. 获取绑定sql

 public BoundSql getBoundSql(Object parameterObject) {
    //从sqlSource获取绑定的sql对象
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    //占用传入的参数映射对象,也就是有多少个?就有多少个映射对象
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //如果没有就新建一个BoundSql对象
    if (parameterMappings == null || parameterMappings.isEmpty()) {
      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }

    // check for nested result maps in parameter mappings (issue #30)
    //result map相关处理逻辑,目前没有研究
    for (ParameterMapping pm : boundSql.getParameterMappings()) {
      String rmId = pm.getResultMapId();
      if (rmId != null) {
        ResultMap rm = configuration.getResultMap(rmId);
        if (rm != null) {
          hasNestedResultMaps |= rm.hasNestedResultMaps();
        }
      }
    }

    return boundSql;
  }


又涉及了从sqlSource获取绑定sql,比较复杂的是DynamicSqlSource,涉及了<if>标签等的解析逻辑


  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    //上下文信息,主要封装了参数和sqlBuilder构建对象
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    //处理sqlNode对象,把sql拼接到sqlBuilder里面去
    rootSqlNode.apply(context);

    //声明解析器解析#{}的占位符
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    //里面利用了ParameterMappingTokenHandler对#{}进行解析
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    //再获取boundSql,这是解析好的可以发往数据库的sql了。#{}被替换为?了
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }


2. 获取CacheKey,这个就不解析了,就是缓存使用的

这两步做完以后就进入到了



org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)



  @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.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //调用真正的查询,也就是会先进到BaseExecutor的query方法,在下一段分析
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

Executor(BaseExecutor).query

org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)



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



核心的方法其实就是到数据库查询的过程,其他都是在做缓存处理




  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      //执行查询
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      //先移除缓存
      localCache.removeObject(key);
    }
    //查后的数据放到缓存中
    localCache.putObject(key, list);
    //又放到了一个专门的缓存中,StatementType.CALLABLE的情况下
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }



最后就是看doQuery方法了,其他的子类都是覆盖这个进行实现即可,这也就是BaseExecutor存在的模板模式的意义,他封装了一些通用的逻辑,而子类只需要实现即可,不需要再重复的关注这些操作逻辑了

Executor(SimpleExecutor).query

根据前面最终的逻辑就会进入到SimpleExecutor进行执行


org.apache.ibatis.executor.SimpleExecutor#doQuery




  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    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.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }



是不是好像已经看到了最熟悉的代码了,先获取statement对象,再进行prepare,最后再执行查询,下面就一个个点进去看

获取StatementHandler

又是一个接口,总的来说跟Executor的设计差不多,主要有以下的实现

BaseStatementHandler:基础的实现,提供了一些常用通用的方法

PreparedStatementHandler: 最常用的,继承了BaseStatementHandler

CallableStatementHandler:  callable类型,继承了BaseStatementHandler

SimpleStatementHandler: 简单处理器,原生Statement,继承了BaseStatementHandler

RoutingStatementHandler:路由处理器,其实就是把判断代码也封装成一个类管理了,同时保存了以下几个真正的一个实现,调用的时候就是直接调真正的,有兴趣的看一下这个类的实现就明白了,这里就不贴出来了........

以下是创建的流程和逻辑

org.apache.ibatis.session.Configuration#newStatementHandler


  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //先创建一个RoutingStatementHandler,其实就是封装了一个具体实现
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    //这里是mybatis插件实现的位置,又进行了插件的拦截代理生成
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }


第一步其实很简单,看到构造器和具体实现就明白了


  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //根据类型判断同时把他封装给自己,这种有点类似于门面设计模式
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        //默认其实就是这种实现,PreparedStatement类型的
        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());
    }

  }


里面会使用delegate 去实现接口的所有方法



第二步是代理拦截的生成,之前已经说过了,这里就不再细说了


所以创建这个对象仍然还是比较简单的


prepareStatement处理

org.apache.ibatis.executor.SimpleExecutor#prepareStatement


  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //获取数据库链接,每个sqlSession获取的是同一条,所以也是sqlSession不安全的原因所在
    Connection connection = getConnection(statementLog);
    //获取statement对象
    stmt = handler.prepare(connection, transaction.getTimeout());
    //执行参数设置
    handler.parameterize(stmt);
    //返回statement
    return stmt;
  }


这里仍然有几个步骤


1. 获取连接,这个没啥好说的


2. 设置基本参数

  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //初始化
      statement = instantiateStatement(connection);
      //设置超时时间
      setStatementTimeout(statement, transactionTimeout);
      //设置fetchSize
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }


3. 也是最重要的,设置参数


org.apache.ibatis.executor.statement.PreparedStatementHandler#parameterize


最终会到达这个方法

org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters

在这里你会看到核心的TypeHanler的使用设置


  @Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    //获取sql占位符对象,有多少个?就有多少个ParameterMapping对象
    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;
          //参数属性名
          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);
          }
          //获取ParameterMapping对象包含的类型转换器
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            //调用类型转换器设置参数
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          } catch (SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

类型转换器便发生了这里,至于value的取值,目前有些地方我还没搞懂,以后搞懂了再写新的文章进行发布,不过整体逻辑也大概是看下来了

StatementHandler#query

这是最后的一个逻辑,也就是对返回结果的处理,包括怎么封装为对象返回的都在这个里面了,默认使用的是PreparedStatementHandler,也就是我们上面说到的地方

org.apache.ibatis.executor.statement.PreparedStatementHandler#query


  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //转换为PreparedStatement对象
    PreparedStatement ps = (PreparedStatement) statement;
    //执行查询,这是jdbc原生的api,学过的应该都知道
    ps.execute();
    //使用ResultSetHandler进行处理结果集
    return resultSetHandler.<E> handleResultSets(ps);
  }



前面两步还是比较好理解的,最后一部是用于处理结果集的


ResultSetHandler又是一个新的接口,mybatis封装了很多接口,为的是以后方便别人的扩展,所以我们最后只要看ResultSetHandler的DefaultResultSetHandler实现即可,目前只有这个实现,估计大部分人就比较好理解了,再起一个标题块专门来看这个处理集,这个处理方法也是相对比较复杂的,不会说全部,只会说我知道的
handleResultSets方法


而这个默认的是在BaseStatementHandler初始化进行实例化的,可以看到


  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
    //其他的忽略掉了

        
    //参数处理器和结果处理器
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

resultSetHandler.<E> handleResultSets(ps)

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets



  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    //获取ResultMap对象,我们定义的对象被mybatis封装为这个了
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    //校验最少要有一个ResultMap
    validateResultMapsCount(rsw, resultMapCount);
    //循环处理
    while (rsw != null && resultMapCount > resultSetCount) {
      //循环获取,里面包含了 private Class<?> type; 这里的type就是User对象
      ResultMap resultMap = resultMaps.get(resultSetCount);
      //处理结果集,核心方法
      handleResultSet(rsw, resultMap, multipleResults, null);
      //获取下一个结果集
      rsw = getNextResultSet(stmt);
      //清除一些数据
      cleanUpAfterHandlingResultSet();
      //累加
      resultSetCount++;
    }

    //这一块应该是嵌套的resultMap处理,目前没研究..,很久没这么写过了
    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++;
      }
    }

    //进行包装返回,如果是1个直接返回那个,多个还是返回列表
    return collapseSingleResultList(multipleResults);
  }





上面的逻辑并不复杂,还没有到具体的解析代码,接下来看到处理的代码里面去,handleResultSet方法



  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        //parentMapping为空并且resultHandler为空的逻辑处理,我们现在走的是这里
        if (resultHandler == null) {
          //声明默认处理器
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          //处理数据同时把数据放到ResultList中
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          //把处理完的数据拿出来
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          //parentMapping为空并且resultHandler不为空,直接进入到这里来处理,其他的为其他逻辑
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }




  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    //是否有内嵌套的map
    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>();
    //处理偏移量,我们的逻辑也没用到这个,不过mybatis支持这个.可以用来跳过前多少行数据的功能
    //看到这里也让我明白了RowBounds的使用,就是用来跳过前面多少行的
    skipRows(rsw.getResultSet(), rowBounds);
    //调用Result.next开始获取数据进行处理了
    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());
    }
  }

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

  @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
  private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
    //把获取的数据放到下一个去
    resultContext.nextResultObject(rowValue);
    //回调处理把数据放到调用进来的List<Object>中去,这也是一种设计思想,回调模式!
    ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
  }





那么现在的逻辑也是越来越清晰了,解析数据就发生在getRowValue方法中,我们再去里面看看发生了什么



  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //创建结果返回对象,这里也就是调用反射创建了User对象,这个时候还没有附上值
    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;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }



再接着往下看


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



这里再一次看到了类型转换器的设置,同时也看到了使用反射设置对象数据,那么到这里整个逻辑就已经结束了


其他的就是一些分支处理,或者说细节处理,细节的话有兴趣可以再到对应的方法里面去进行分析,这里整个流程差不多就要结束了

last

前面的结果查询后就又回到这个方法了



 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      //执行查询,刚刚就是从这里查询出来的
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      //先移除缓存
      localCache.removeObject(key);
    }
    //查后的数据放到缓存中
    localCache.putObject(key, list);
    //又放到了一个专门的缓存中,StatementType.CALLABLE的情况下
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

到处,整个流程就分析完了,也不知道大家能不能看懂我说的...

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值