mybatis对mapper.xml的解析(二)

对select,insert,update,delete的解析是通过buildStatementFromContext来完成的,具体的解析是XMLStatementBuilder来完成的.

支持的属性有

名称说明
id语句id
databaseId

不处理语句情况

1、在配置文件中设置了databaseIdProvider,并且当前设置的databaseId与配置文件中不一致时

2、配置文件 中没有设置,当前设置了databaseId

3、配置文件中没有设置databaseIdProvider,当前没有设置databaseId,有当前id对应的MappedStatement的databaseId不等于null

flushCache布尔值,如果没有设置情况下,如果是select语句,则默认为false,否则为true
useCache布尔值,如果没有设置情况上,select语句默认是true,否则为false
resultOrdered布尔值,没有设置时,默认是false
parameterType设置语句请求参数类型,可以使用别名
lang设置语言驱动器,默认是XMLLanguageDriver
selectKey生成主键节点
useGeneratedKey如果没有设置,使用全局配置及当前语句是不是插入语句 。如果为true,则使用Jdbc3KeyGenerator,否则使用NoKeyGenerator
statementType没有设置时默认是PREPARE类型
fetchSize在StatementHandler中使用,来设置获取大小。
timeout在StatementHandler中设置语句的执行超时时间
parameterMap参数映射,已经不推荐使用
resultType一种特殊的resultMap
resultMap与resultType相当,两者二选一
resultSetType用于在StatementHandler中设置语句的ResultType的类型
keyProperty用于设置主属性,有多个属性时,用逗号分隔。用于KeyGenerator
keyColumn用于设置数据库字段主键,有多个时,用逗号分隔。用于KeyGenerator以及用于StatementHandler初始化语句时
resultSets有多个时,用逗号分隔。用于ResultSetHandler处理

selectKey支持的属性

名称说明
databaseId

不处理语句情况

1、在配置文件中设置了databaseIdProvider,并且当前设置的databaseId与配置文件中不一致时

2、配置文件 中没有设置,当前设置了databaseId

3、配置文件中没有设置databaseIdProvider,当前没有设置databaseId,有当前id对应的MappedStatement的databaseId不等于null

resultType返回的数据类型
statementType如果没有设置,默认是PREPARE类型
keyProperty主属性
keyColumn数据库主键
order在什么时候执行,没有设置时,默认是AFTER

1、解析语句中的include

XMLIncludeTransformer在解析include节点时,首先找到refid引用的节点,同时解析子节点property的name,value值对。接着在refid的引用的节点上应用applyIncludes递归调用。递归完后,用引用节点替换indlude节点。将引用节点的子结点添加到include之前,然后删除include节点。

在解析非include节点且节点类型是ELEMENT_NODE时,递归遍历子节点

如果解析的是引用节点,且节点是文本结点会作变量替换。

private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
    if (source.getNodeName().equals("include")) {
      Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
      Properties toIncludeContext = getVariablesContext(source, variablesContext);
      applyIncludes(toInclude, toIncludeContext, true);
      if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
        toInclude = source.getOwnerDocument().importNode(toInclude, true);
      }
      source.getParentNode().replaceChild(toInclude, source);
      while (toInclude.hasChildNodes()) {
        toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
      }
      toInclude.getParentNode().removeChild(toInclude);
    } else if (source.getNodeType() == Node.ELEMENT_NODE) {
      NodeList children = source.getChildNodes();
      for (int i = 0; i < children.getLength(); i++) {
        applyIncludes(children.item(i), variablesContext, included);
      }
    } else if (included && source.getNodeType() == Node.TEXT_NODE
        && !variablesContext.isEmpty()) {
      // replace variables ins all text nodes
      source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
    }
  }

2、解析selectKey节点

此结点在insert节点下,解析后添加到configuration中的keyGenerators中,添加后,删除selectKey节点

private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
    List<XNode> selectKeyNodes = context.evalNodes("selectKey");
    if (configuration.getDatabaseId() != null) {
      parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
    }
    parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
    removeSelectKeyNodes(selectKeyNodes);
  }

private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
    for (XNode nodeToHandle : list) {
      String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
      String databaseId = nodeToHandle.getStringAttribute("databaseId");
      if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
        parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
      }
    }
  }

  private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
    String resultType = nodeToHandle.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
    String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
    boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));

    //defaults
    boolean useCache = false;
    boolean resultOrdered = false;
    KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
    Integer fetchSize = null;
    Integer timeout = null;
    boolean flushCache = false;
    String parameterMap = null;
    String resultMap = null;
    ResultSetType resultSetTypeEnum = null;

    SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
    SqlCommandType sqlCommandType = SqlCommandType.SELECT;

    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);

    id = builderAssistant.applyCurrentNamespace(id, false);

    MappedStatement keyStatement = configuration.getMappedStatement(id, false);
    configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
  }

private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
    for (XNode nodeToHandle : selectKeyNodes) {
      nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
    }
  }

3、根据参数类型创建SqlSource

包含解析动态节点,创建DynamicSqlSource或者RawSqlSource

SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);

4、创建MappedStatement,添加到Configuration中

 

//XMLStatementBuilder
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kgduu

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值