源码解析:mybatis调用链之XMLStatementBuilder解析解析sql语句节点

该过程由XMLMapperBuilderconfigurationElement方法触发:

XMLMapperBuilder

private void configurationElement(XNode context) {
    try {
        //获取mapper节点的namespace属性
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      //设置builderAssistant的namespace属性
      builderAssistant.setCurrentNamespace(namespace);
      //解析cache-ref节点
      cacheRefElement(context.evalNode("cache-ref"));
      //重点分析 :解析cache节点----------------1-------------------
      cacheElement(context.evalNode("cache"));
      //解析parameterMap节点(已废弃)
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //重点分析 :解析resultMap节点(基于数据结果去理解)----------------2-------------------
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //解析sql节点
      sqlElement(context.evalNodes("/mapper/sql"));
      //重点分析 :解析select、insert、update、delete节点 ----------------3-------------------
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
  }

调用buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

XMLMapperBuilder

 //解析select、insert、update、delete节点
  private void buildStatementFromContext(List list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    buildStatementFromContext(list, null);
  }

调用private void buildStatementFromContext(List list, String requiredDatabaseId)

XMLMapperBuilder

//处理所有的sql语句节点并注册至configuration对象
  private void buildStatementFromContext(List list, String requiredDatabaseId) {
    for (XNode context : list) {
      //创建XMLStatementBuilder 专门用于解析sql语句节点
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        //解析sql语句节点
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }

该方法新建XMLStatementBuilder对象,对象构建过程:

首先XMLStatementBuilder类继承于BaseBuilder,与XMLStatementBuilder、XMLConfigBuilder一样调用BaseBuilder构造方法,初始化属性configuration、typeAliasRegistry、typeHandlerRegistry值。

然后初始化builderAssistant(该属性的值由XMLMapperBuilder传入,首次赋值在XMLMapperBuilder构造方法中)、context、requiredDatabaseId属性值。

XMLStatementBuilder对象初始化完成后,执行statementParser.parseStatementNode();解析过程:

XMLStatementBuilder

public void parseStatementNode() {
    //获取sql节点的id
    String id = context.getStringAttribute("id");
    String databaseId = context.getStringAttribute("databaseId");

    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }
    /*获取sql节点的各种属性*/
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String parameterType = context.getStringAttribute("parameterType");
    Class parameterTypeClass = resolveClass(parameterType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultType = context.getStringAttribute("resultType");
    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);

    Class resultTypeClass = resolveClass(resultType);
    String resultSetType = context.getStringAttribute("resultSetType");
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

    
    
    //根据sql节点的名称获取SqlCommandType(INSERT, UPDATE, DELETE, SELECT)
    String nodeName = context.getNode().getNodeName();
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

    // Include Fragments before parsing
    //在解析sql语句之前先解析节点
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    // Parse selectKey after includes and remove them.
    //在解析sql语句之前,处理子节点,并在xml节点中删除
    processSelectKeyNodes(id, parameterTypeClass, langDriver);
    
    // Parse the SQL (pre:  and  were parsed and removed)
    //解析sql语句是解析mapper.xml的核心,实例化sqlSource,使用sqlSource封装sql语句
    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    String resultSets = context.getStringAttribute("resultSets");//获取resultSets属性
    String keyProperty = context.getStringAttribute("keyProperty");//获取主键信息keyProperty
    String keyColumn = context.getStringAttribute("keyColumn");///获取主键信息keyColumn
    
    //根据获取对应的SelectKeyGenerator的id
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    
    
    //获取keyGenerator对象,如果是insert类型的sql语句,会使用KeyGenerator接口获取数据库生产的id;
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }

    //通过builderAssistant实例化MappedStatement,并注册至configuration对象
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered, 
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

通过MapperBuilderAssistant实例化MappedStatement,并注册至configuration对象

MapperBuilderAssistant

public MappedStatement addMappedStatement(
      String id,
      SqlSource sqlSource,
      StatementType statementType,
      SqlCommandType sqlCommandType,
      Integer fetchSize,
      Integer timeout,
      String parameterMap,
      Class parameterType,
      String resultMap,
      Class resultType,
      ResultSetType resultSetType,
      boolean flushCache,
      boolean useCache,
      boolean resultOrdered,
      KeyGenerator keyGenerator,
      String keyProperty,
      String keyColumn,
      String databaseId,
      LanguageDriver lang,
      String resultSets) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }

    id = applyCurrentNamespace(id, false);
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource)
        .fetchSize(fetchSize)
        .timeout(timeout)
        .statementType(statementType)
        .keyGenerator(keyGenerator)
        .keyProperty(keyProperty)
        .keyColumn(keyColumn)
        .databaseId(databaseId)
        .lang(lang)
        .resultOrdered(resultOrdered)
        .resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id))
        .resultSetType(resultSetType)
        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
        .useCache(valueOrDefault(useCache, isSelect))
        .cache(currentCache);

    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    MappedStatement statement = statementBuilder.build();
    configuration.addMappedStatement(statement);
    return statement;
  }

此处可以看到,MappedStatement中使用了MapperBuilderAssistant对象的currentCache(二级缓存)。

在MappedStatement.Builder构建过程中,

.flushCacheRequired(valueOrDefault(flushCache, !isSelect)

此处flushCache的值表明了是否需要清除一级缓存。默认查询的时候,不需要清除,其他操作都要清除。在分布式系统中,若需要清控一级缓存,则配置flushCache为true即可。效果上相当于关闭了该sql的一级缓存。

你可能感兴趣的:(mybatis)