mybatis源码(五)

178 阅读6分钟

本篇文章主要介绍mybatis查询数据库。

1、查询数据库

BaseExecutor#queryFromDatabase

public abstract class BaseExecutor implements Executor {
  
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
      List<E> list;
      /**
       * 向一级缓存里put一个占位符
       */
      localCache.putObject(key, EXECUTION_PLACEHOLDER);
      try {
        /**
         * 执行查询
         */
        //SimpleExeuctor
        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

数据库查询流程

1、生成StatementHandler
2、? 参数赋值
3、执行查询
public class SimpleExecutor extends BaseExecutor {

    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();
        
        //1.1 生成StatementHandler
        /**
         * 代理StatementHandler 用你的插件去代理
         *  在 StatementHandler的子类 BaseStatementHandler中 会对ParameterHandler和ResultSetHandler进行代理
         *
         */
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        
        //1.2 ? 赋值
        /**
         * 1、返回一个PrepareStatement
         * 2、给?设置值 #{}在mybatis启动的时候就被替换成?
         */
        stmt = prepareStatement(handler, ms.getStatementLog());
        
        //1.3 执行查询
        //RoutingStatementHandler
        return handler.query(stmt, resultHandler);
      } finally {
        closeStatement(stmt);
      }
    }
}

1.1 StatementHandler

mybatis四大对象之一的StatementHandler的创建流程:

1、创建RoutingStatementHandler
带有${}的sql由jdbc的Statement对象执行,带有#{}的sql对象由jdbc的PreparedStatement执行,因此RoutingStatementHandler的作用就是根据sql的类型,调用具体的Statement执行sql
2、应用插件到StatementHandler

image.png

Configuration#newStatementHandler

public class Configuration {
 
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
      
      /**
       * 创建具有路由功能的StatementHandler
       * 如上,RoutingStatementHandler 的构造方法会根据 MappedStatement 中的 statementType 变量创建不同的 StatementHandler 实现类。
       * 默认情况下,statementType 值为 PREPARED 对应的jdbc里的PreparedStatement
       */
      StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
      /**
       * 代理StatementHandler 用你的插件去代理
       * 应用插件到StatementHandler
       */
      statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
      return statementHandler;
    }
}

RoutingStatementHandler

StatementHandler是mybatis对jdbc的Statement的封装,RoutingStatementHandler是对其他三个StatementHanlder的封装,只是负责上面三个StatementHandler的创建及调用。

public class RoutingStatementHandler implements StatementHandler {
    
  //被装饰的StatementHanlder
  private final StatementHandler delegate;

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

    // 根据 StatementType 创建不同的 StatementHandler
    switch (ms.getStatementType()) {
      case STATEMENT:
        //管理 Statement 对象并向数据库中推送不需要预编译的SQL语句
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        // 管理 Statement 对象并向数据中推送需要预编译的SQL语句,
        /**
         * 父类构造方法中创建ParameterHandler和ResultSetHandler
         */
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        //管理 Statement 对象并调用数据库中的存储过程
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }
}

继续分析PreparedStatementHandler的创建流程 PreparedStatementHandler

public class PreparedStatementHandler extends BaseStatementHandler {

  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //父类构造器
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }
}

BaseStatementHandler

public abstract class BaseStatementHandler implements StatementHandler {

    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;

      /**
       * 代理parameterHandler
       */
      this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
      /**
       * 代理resultSetHandler
       */
      this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
    }

}

在BaseStatementHandler构造器内部,创建了ParameterHandler和ResultSetHandler对象。至此,mybatis四大对象均以创建完毕。至于这几个对象被称为mybatis四大对象的原因,就是只有这四个对象能被mybatis代理,即添加插件。因为Configuration在创建这几个对象时,都调用了interceptorChain.pluginAll进行代理。

1.2 ? 赋值

SimpleExecutor#prepareStatement

public class SimpleExecutor extends BaseExecutor {
   
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
      Statement stmt;
      /**
       *  获取数据库连接
       */
      Connection connection = getConnection(statementLog);
      //1.2.1 创建jdbc的PreparedStatment
      /**
       * 返回一个Statement
       */
      //RoutingStatementHandler#prepare
      stmt = handler.prepare(connection, transaction.getTimeout());
      //1.2.2 参数赋值
      /**
       * 为 PreparedStatement 设置 IN 参数 : ? 赋值
       */
      //RoutingStatementHandler.parameterize
      handler.parameterize(stmt);
      return stmt;
    }
}

1.2.1 创建jdbc的PreparedStatment

RoutingStatementHandler#prepare

public class RoutingStatementHandler implements StatementHandler {

    private final StatementHandler delegate;
   
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
      //BaseStatementHandler#prepare
      return delegate.prepare(connection, transactionTimeout);
    }

  
}

BaseStatementHandler#prepare

public abstract class BaseStatementHandler implements StatementHandler {

    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
      ErrorContext.instance().sql(boundSql.getSql());
      Statement statement = null;
      try {
        //创建jdbc的Statement
        //PreparedStatementHandler#instantiateStatement
        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

public class PreparedStatementHandler extends BaseStatementHandler {
 
    protected Statement instantiateStatement(Connection connection) throws SQLException {
      String sql = boundSql.getSql();
      //调用jdbc的api创建PreparedStatement
      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) {
        return connection.prepareStatement(sql);
      } else {
        return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
      }
    }

}

1.2.2 为 ? 赋值

RoutingStatementHandler.parameterize

public class RoutingStatementHandler implements StatementHandler {

    public void parameterize(Statement statement) throws SQLException {
      delegate.parameterize(statement);
    }

}

PreparedStatementHandler#parameterize

public class PreparedStatementHandler extends BaseStatementHandler {
   
    public void parameterize(Statement statement) throws SQLException {
      /**
       *  通过参数处理器 ParameterHandler 设置方法参数到 PreparedStatement 中
       */
      parameterHandler.setParameters((PreparedStatement) statement);
    }
}

DefaultParameterHandler#setParameters

public class DefaultParameterHandler implements ParameterHandler {
   
    public void setParameters(PreparedStatement ps) {
      ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
      /**
       * sql中所有的#{占位符}中的占位符   在解析Mapper文件时#{}就被替换成 ?
       */
      /**
       * 从 BoundSql 中获取 ParameterMapping 列表,每个 ParameterMapping
       * 与原始 SQL 中的 #{xxx} 占位符一一对应
       */
      List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
      if (parameterMappings != null) {
        for (int i = 0; i < parameterMappings.size(); i++) {
          ParameterMapping parameterMapping = parameterMappings.get(i);
          // 检测参数类型,排除掉 mode 为 OUT 类型的 parameterMapping
          if (parameterMapping.getMode() != ParameterMode.OUT) {
            Object value;
            //获取属性名
            String propertyName = parameterMapping.getProperty();
            if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            //检测 BoundSql 的 additionalParameters 是否包含 propertyName
              value = boundSql.getAdditionalParameter(propertyName);
            } else if (parameterObject == null) {
              value = null;
              // 检测运行时参数是否有相应的类型解析器
            } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
              /**
               * 若运行时参数的类型有相应的类型处理器 TypeHandler,则将
               * parameterObject 设为当前属性的值。
               */
              value = parameterObject;
            } else {
              //为用户传入的参数 parameterObject 创建元信息对象
              MetaObject metaObject = configuration.newMetaObject(parameterObject);
              //从用户传入的参数中获取 propertyName 对应的值
              value = metaObject.getValue(propertyName);
            }

            //以上为获取 #{xxx} 占位符属性所对应的运行时参数
            //*************************************************
            // 分割线以下的代码则是获取 #{xxx} 占位符属性对应的 TypeHandler,并在最后通过 TypeHandler 将运行时参数值设置到 PreparedStatement 中

            TypeHandler typeHandler = parameterMapping.getTypeHandler();
            JdbcType jdbcType = parameterMapping.getJdbcType();
            if (value == null && jdbcType == null) {
              // 此处 jdbcType = JdbcType.OTHER
              jdbcType = configuration.getJdbcTypeForNull();
            }
            try {
              //BaseTypeHandler
              //由类型处理器 typeHandler 向 ParameterHandler 设置参数
              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);
            }
          }
        }
      }
    }
}

1.3 执行查询

RoutingStatementHandler#query

public class RoutingStatementHandler implements StatementHandler {
   
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
      //PreparedStatement
      return delegate.<E>query(statement, resultHandler);
    }

}

PreparedStatementHandler#query

调用jdbc原生api查询数据库,然后处理返回的结果集

public class PreparedStatementHandler extends BaseStatementHandler {

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
      PreparedStatement ps = (PreparedStatement) statement;
      /**
       * 执行查询 这是jdbc原生PreparedStatement的方法
       */
      ps.execute();
      /**
       * 处理返回结果集
       */
      return resultSetHandler.handleResultSets(ps);
    }
}

DefaultResultSetHandler.handleResultSets

结果集处理这块还是优点复杂的,感兴趣的同学可以深入了解下。

public class DefaultResultSetHandler implements ResultSetHandler {
 
    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对象,
      // ResultSetWrapper对象含有已映射和未映射的列名和属性的对应关系
      ResultSetWrapper rsw = getFirstResultSet(stmt);
      // 获取所有的ResultMap
      List<ResultMap> resultMaps = mappedStatement.getResultMaps();
      // ResultMap的个数
      int resultMapCount = resultMaps.size();
      // 校验:如果结果集有数据,但是没有定义返回的结果类型,就会报错
      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 ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
      /**
       * 获取结果集
       */
      ResultSet rs = stmt.getResultSet();
      while (rs == null) {
        /**
         * 移动 ResultSet 指针到下一个上,有些数据库驱动可能需要使用者先调用 getMoreResults 方法,然后才能调用 getResultSet 方法
         * 获取到第一个 ResultSet
         */
        // 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;
          }
        }
      }
      /**
       * 将ResultSet封装到 ResultSetWrapper 中。
       * ResultSetWrapper 中包含了 ResultSet 一些元信息,比如列名称、每列对应的 JdbcType、
       * 以及每列对应的 Java 类名(class name,譬如 java.lang.String)等。
       */
      return rs != null ? new ResultSetWrapper(rs, configuration) : null;
    }
    

    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);
            // 将处理结果放到list集中
            multipleResults.add(defaultResultHandler.getResultList());
          } else {
            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 {
      // 如果有嵌套的ResultMap
      if (resultMap.hasNestedResultMaps()) {
        ensureNoRowBounds();
        checkResultHandler();
        // 处理含有嵌套ResultMap的结果
        handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
      } else {
        // 处理不含有嵌套ResultMap的结果
        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<>();
      ResultSet resultSet = rsw.getResultSet();
      // 跳过已处理的行
      skipRows(resultSet, rowBounds);
      while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        //获取行值
        Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        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())) {
        // 将行值包装成元数据对象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;
    }


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

    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);
        //类型处理器
        return typeHandler.getResult(rs, column);
      }
    }
}