解析Mapper.xml - 图1

解析Mapper.xml - 图2 在 XMLScriptBuilder 的parseScriptNode()方法中解析每个sql语句。

  1. package org.apache.ibatis.scripting.xmltags;
  2. public class XMLScriptBuilder extends BaseBuilder {
  3. public SqlSource parseScriptNode() {
  4. MixedSqlNode rootSqlNode = parseDynamicTags(context);
  5. SqlSource sqlSource;
  6. if (isDynamic) {
  7. sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
  8. } else {
  9. sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
  10. }
  11. return sqlSource;
  12. }
  13. protected MixedSqlNode parseDynamicTags(XNode node) {
  14. List<SqlNode> contents = new ArrayList<>();
  15. NodeList children = node.getNode().getChildNodes();
  16. for (int i = 0; i < children.getLength(); i++) {
  17. XNode child = node.newXNode(children.item(i));
  18. if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
  19. String data = child.getStringBody("");
  20. TextSqlNode textSqlNode = new TextSqlNode(data);
  21. if (textSqlNode.isDynamic()) {
  22. contents.add(textSqlNode);
  23. isDynamic = true;
  24. } else {
  25. contents.add(new StaticTextSqlNode(data));
  26. }
  27. } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
  28. String nodeName = child.getNode().getNodeName();
  29. NodeHandler handler = nodeHandlerMap.get(nodeName);
  30. if (handler == null) {
  31. throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
  32. }duan
  33. handler.handleNode(child, contents);
  34. isDynamic = true;
  35. }
  36. }
  37. return new MixedSqlNode(contents);
  38. }
  39. }

上面parseDynamicTags方法中判断sql语句中是否有“${}”,如果有一个地方含有动态语句,则这个sql就是动态sql,即为DynamicSqlSource类型,否则为RawSqlSource类型。

解析静态sql

package org.apache.ibatis.scripting.defaults;

public class RawSqlSource implements SqlSource {

  private final SqlSource sqlSource;

  public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {
    this(configuration, getSql(configuration, rootSqlNode), parameterType);
  }

  public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> clazz = parameterType == null ? Object.class : parameterType;
    sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>());
  }

  private static String getSql(Configuration configuration, SqlNode rootSqlNode) {
    DynamicContext context = new DynamicContext(configuration, null);
    rootSqlNode.apply(context);
    return context.getSql();
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    return sqlSource.getBoundSql(parameterObject);
  }

}

由上面代码可以看出,对于静态sql,其在构建RawSqlSource对象时,就会解析sql。例如将”#{}”替换为”?”。

在解析时,对于标签例如:WhereSqlNode、IfSqlNode 以及含有${}的TextSqlNode等都是动态DynamicSqlSource,文本内容保持不变,例如IfSqlNode的sqlSource为”name = #{name,jdbcType=VARCHAR}”,而TextSqlNode中包含${}时sqlSource为”id = ${id}”,其他静态TextSqlNode则会将”#{}”替换为”?”。