mybatis源码之执行查询SQL代码分析

本文将通过阅读mybatis源码的方式详细分析mybatis查询的执行流程。

系列文档:


执行SQL源码分析

还是使用之前的示例代码。

示例代码入口

public void testSelectBlogByBlogSearchParameter() throws ParseException {

  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  List<Integer> ids = new ArrayList<>();
  ids.add(1);
  ids.add(2);

  Blog blog = new Blog();
  blog.setContent("mybatis源码分析");
  blog.setTitle("mybatis");

  BlogSearchParameter parameter = new BlogSearchParameter();
  parameter.setId(1);
  parameter.setIds(ids);
  parameter.setCreateTime(format.parse("2020-01-01 00:00:00"));

  parameter.setBlog(blog);

  List<Blog> list = session.selectList(
      "org.net5ijy.mybatis.test.BlogMapper.selectBlogByParameter", parameter);

  for (Blog b : list) {
    System.out.println(b);
  }
}

session.selectList方法

从之前openSession方法的分析可以知道这里使用的是DefaultSqlSession类型。

如下是方法实现:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    // 这里的statement是MappedStatement的包含namespace的id全名
    // 实际上就是从id -> MappedStatement映射中获取
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(
        ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("");
  } finally {
    ErrorContext.instance().reset();
  }
}

wrapCollection方法就是把list和array类型的参数做了以下封装,这里的key名值的注意:

public static Object wrapToMapIfCollection(Object object, String actualParamName) {
  if (object instanceof Collection) {
    ParamMap<Object> map = new ParamMap<>();
    map.put("collection", object);
    if (object instanceof List) {
      map.put("list", object);
    }
    Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
    return map;
  } else if (object != null && object.getClass().isArray()) {
    ParamMap<Object> map = new ParamMap<>();
    map.put("array", object);
    Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
    return map;
  }
  return object;
}

executor.query方法

这个方法有两个实现,一个在BaseExecutor中,一个在CachingExecutor中,在之前创建Executor的时候,由于cacheEnabled默认是true,所以创建的是CachingExecutor对象,但是cache不是本次源码分析的重点内容(留到深入分析中做),遇到cache时会略过不做展开分析:

public <E> List<E> query(
    MappedStatement ms, Object parameterObject,
    RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  // 获取BoundSql
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  // 创建CacheKey
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  // 重载query
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

获取BoundSql

BoundSql boundSql = ms.getBoundSql(parameterObject);

实现代码:

public BoundSql getBoundSql(Object parameterObject) {
  BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings == null || parameterMappings.isEmpty()) {
    boundSql = 
        new BoundSql(configuration, boundSql.getSql(),
                     parameterMap.getParameterMappings(), parameterObject);
  }

  // 这里有一个嵌套ResultMap的检查
  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;
}

重载query

public <E> List<E> query(
    MappedStatement ms, Object parameterObject,
    RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  // cache是null
  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;
    }
  }
  // 所以直接执行到这里了
  // 这里就是执行的BaseExecutor的query方法
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

// BaseExecutor的query方法
// 内部不重要的代码就删除掉了,不再记录
public <E> List<E> query(
    MappedStatement ms, Object parameter,
    RowBounds rowBounds, ResultHandler resultHandler,
    CacheKey key, BoundSql boundSql) throws SQLException {

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

queryStack、deferredLoads这些内容与嵌套查询、延迟加载、缓存等特性有关,暂时省略,不做展开分析,留到深入分析中做。

queryFromDatabase查询流程

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);
  if (ms.getStatementType() == StatementType.CALLABLE) {
    localOutputParameterCache.putObject(key, parameter);
  }
  return list;
}

// SimpleExecutor.doQuery
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
    // 创建的是RoutingStatementHandler对象
    // 而RoutingStatementHandler内部又根据ms.getStatementType()的值创建了不同类型的StatementHandler
    // 在示例代码中,ms.getStatementType()的值是PREPARED,所以实际上创建的是PreparedStatementHandler对象
    StatementHandler handler = 
        configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    // 创建JDBC的Statement
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 查询数据
    return handler.query(stmt, resultHandler);
  } finally {
    // 关闭Statement
    closeStatement(stmt);
  }
}

public StatementHandler newStatementHandler(
    Executor executor, MappedStatement mappedStatement,
    Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  StatementHandler statementHandler = new RoutingStatementHandler(
      executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  // 插件代理
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

prepareStatement创建JDBC Statement

stmt = prepareStatement(handler, ms.getStatementLog());

prepareStatement方法:

private Statement prepareStatement(
    StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  // 获取JDBC连接
  Connection connection = getConnection(statementLog);
  // 获取Statement
  stmt = handler.prepare(connection, transaction.getTimeout());
  // 给Statement设置参数
  handler.parameterize(stmt);
  return stmt;
}

protected Connection getConnection(Log statementLog) throws SQLException {
  // 从JdbcTransaction获取JDBC连接
  // 实际上就是从DataSource获取连接
  // 从之前的数据源配置源码分析可以得知,这里使用的是PooledDataSource的实例
  Connection connection = transaction.getConnection();
  if (statementLog.isDebugEnabled()) {
    return ConnectionLogger.newInstance(connection, statementLog, queryStack);
  } else {
    return connection;
  }
}

handler.prepare(connection, transaction.getTimeout())方法,实际上实现代码在BaseStatementHandler中:

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
  Statement statement = null;
  try {
    // 这行代码比较重要,在PreparedStatementHandler类中
    statement = instantiateStatement(connection);
    setStatementTimeout(statement, transactionTimeout);
    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);
  }
}

// PreparedStatementHandler.instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
  String sql = boundSql.getSql();
  // 这个分支此处不做展开分析,在深入分析中补充
  if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
    String[] keyColumnNames = mappedStatement.getKeyColumns();
    if (keyColumnNames == null) {
      return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
    } else {
      return connection.prepareStatement(sql, keyColumnNames);
    }
  } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
    // 执行的是这个分支
    // 就是JDBC的代码
    return connection.prepareStatement(sql);
  } else {
    return connection.prepareStatement(
        sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  }
}

给Statement设置参数,handler.parameterize(stmt)方法,这里比较重要:

// PreparedStatementHandler.parameterize
public void parameterize(Statement statement) throws SQLException {
  parameterHandler.setParameters((PreparedStatement) statement);
}

DefaultParameterHandler.setParameters方法:

public void setParameters(PreparedStatement ps) {
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings != null) {
    // 遍历parameterMapping
    // 和SQL中的?是一一对应的关系
    // 遍历结束之后,SQL中的每个参数都会被赋值
    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)) {
          // additionalParameter此处不展开,在深入分析中补充
          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 typeHandler = parameterMapping.getTypeHandler();
        // Jdbc类型
        JdbcType jdbcType = parameterMapping.getJdbcType();
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        try {
          // 给Statement设置参数
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException | SQLException e) {
          throw new TypeException("...");
        }
      }
    }
  }
}

typeHandler.setParameter方法的示例:

public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
  if (parameter == null) {
    if (jdbcType == null) {
      throw new TypeException("");
    }
    try {
      // 给Statement设置null值
      ps.setNull(i, jdbcType.TYPE_CODE);
    } catch (SQLException e) {
      throw new TypeException("...");
    }
  } else {
    try {
      // 设置非null值
      setNonNullParameter(ps, i, parameter, jdbcType);
    } catch (Exception e) {
      throw new TypeException("...");
    }
  }
}

// 以IntegerTypeHandler为例
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
    throws SQLException {
  ps.setInt(i, parameter);
}

StatementHandler.query方法

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  // 执行JDBC查询
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();
  // 处理查询结果
  return resultSetHandler.handleResultSets(ps);
}

处理结果集

resultSetHandler.handleResultSets方法,这个方法有很多用于处理多结果集和关联查询的内容,平时没有使用过,对其中的原理不是很了解,所以此处的分析仅限于单结果集,高级的内容留到后续的深入分析中去做:

public List<Object> handleResultSets(Statement stmt) throws SQLException {

  // 封装查询结果
  final List<Object> multipleResults = new ArrayList<>();

  int resultSetCount = 0;
  // 获取并封装JDBC查询的ResultSet
  ResultSetWrapper rsw = getFirstResultSet(stmt);

  // 通常仅有一个ResultMap元素
  List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  // 值为1
  int resultMapCount = resultMaps.size();
  // 结果集和resultMapCount的合法性验证
  validateResultMapsCount(rsw, resultMapCount);
  // 在现阶段的分析中,此循环仅执行一次
  while (rsw != null && resultMapCount > resultSetCount) {
    // 获取ResultMap
    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);
}

private void handleResultSet(
    ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
    ResultMapping parentMapping) throws SQLException {
  try {
    if (parentMapping != null) {
      handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    } else {
      // 执行这个分支
      if (resultHandler == null) {
        // 执行这个分支
        DefaultResultHandler defaultResultHandler =
            new DefaultResultHandler(objectFactory);
        // 处理结果集
        handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        // 把结果放入集合
        multipleResults.add(defaultResultHandler.getResultList());
      } else {
        handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      }
    }
  } finally {
    closeResultSet(rsw.getResultSet());
  }
}

public void handleRowValues(
    ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
    RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  // 嵌套查询留到后续的深入分析去做,这里只分析else分支
  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<>();
  // 这里获取到JDBC的ResultSet对象
  ResultSet resultSet = rsw.getResultSet();
  // 一个跳行处理
  skipRows(resultSet, rowBounds);
  // resultSet.next()获取下一行结果,这是JDBC的代码
  while (shouldProcessMoreRows(resultContext, rowBounds) &&
         !resultSet.isClosed() &&
         resultSet.next()) {
    ResultMap discriminatedResultMap =
        resolveDiscriminatedResultMap(resultSet, resultMap, null);
    // 封装一行结果
    Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
    // resultHandler是DefaultResultHandler的实例
    // 这行代码的作用就是从resultContext中获取到结果然后保存到resultHandler中
    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
  }
}

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())) {
    // 获取行数据类型的元信息,包括对象本身、数据类型、
    // setter、getter、默认构造方法等
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    // 值为false
    boolean foundValues = this.useConstructorMappings;
    // 对于resultMap中没有做映射的列做自动化映射处理
    // 代码比较多,但是思路与普通映射一样,不展开分析了
    if (shouldApplyAutomaticMappings(resultMap, false)) {
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) ||
                    foundValues;
    }
    // 使用JDBC行结果为行数据对象填充属性值
    foundValues = applyPropertyMappings(
        rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ?
        rowValue : null;
  }
  return rowValue;
}

private boolean applyPropertyMappings(
    ResultSetWrapper rsw, ResultMap resultMap,
    MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
    throws SQLException {
  // 被映射列
  final List<String> mappedColumnNames =
      rsw.getMappedColumnNames(resultMap, columnPrefix);
  boolean foundValues = false;
  final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
  // 遍历结束之后,一行数据对象就封装完成了
  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);
      // 获取属性名
      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())) {
        // 为对象的指定属性赋值
        metaObject.setValue(property, value);
      }
    }
  }
  return foundValues;
}

返回查询结果

return collapseSingleResultList(multipleResults);

collapseSingleResultList方法:

private List<Object> collapseSingleResultList(List<Object> multipleResults) {
  return multipleResults.size() == 1 ?
      (List<Object>) multipleResults.get(0) : multipleResults;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值