动态sql解析源码分析

概述

动态sql解析源码分析_第1张图片
我们在mapper.xml中写的这种sql并不能执行,这就要求mybatis将我们编写的sql进行解析,变成符合w3c标准的sql,让statement可以执行,这种脚本解析很多场景都会使用,比如我们工作中使用的流程编排,规则解析,freemark框架等都会存在这样的技术

总体架构

动态sql解析源码分析_第2张图片

  • BoundSql :这个类我们不陌生,在前面分析的时候经常遇到,这个类中提供了satement 运行sql所需要的所有数据
  • SqlSource 非常简单的一个接口,就一个获取BoudSql方法

DynamicSqlSource 动态解析

动态sql解析源码分析_第3张图片
源码

 @Override
  public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    context.getBindings().forEach(boundSql::setAdditionalParameter);
    return boundSql;
  }

SqlNode 语法树解析

脚本组成
动态sql解析源码分析_第4张图片
动态sql解析源码分析_第5张图片
eg:


动态sql解析源码分析_第6张图片
源代码:

org.apache.ibatis.scripting.xmltags.XMLScriptBuilder#parseDynamicTags
protected MixedSqlNode parseDynamicTags(XNode node) {
    List contents = new ArrayList<>();
    NodeList children = node.getNode().getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
      XNode child = node.newXNode(children.item(i));
      //文本结点
      if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
        String data = child.getStringBody("");
        TextSqlNode textSqlNode = new TextSqlNode(data);
        if (textSqlNode.isDynamic()) {
          contents.add(textSqlNode);
          isDynamic = true;
        } else {
          contents.add(new StaticTextSqlNode(data));
        }
        //动态结点 eg:  等等
      } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
        String nodeName = child.getNode().getNodeName();
        NodeHandler handler = nodeHandlerMap.get(nodeName);
        if (handler == null) {
          throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
        }
        handler.handleNode(child, contents);
        isDynamic = true;
      }
    }
    return new MixedSqlNode(contents);
  }

每个点点等处理器中handleNode 方法会调用parseDynamicTags 形成一个递归操作;
解析流程图:
动态sql解析源码分析_第7张图片

private void initNodeHandlerMap() {
    nodeHandlerMap.put("trim", new TrimHandler());
    nodeHandlerMap.put("where", new WhereHandler());
    nodeHandlerMap.put("set", new SetHandler());
    nodeHandlerMap.put("foreach", new ForEachHandler());
    nodeHandlerMap.put("if", new IfHandler());
    nodeHandlerMap.put("choose", new ChooseHandler());
    nodeHandlerMap.put("when", new IfHandler());
    nodeHandlerMap.put("otherwise", new OtherwiseHandler());
    nodeHandlerMap.put("bind", new BindHandler());
  }

提前初始化一些处理器;

动态sql解析源码分析_第8张图片

你可能感兴趣的:(#,mybatis,1024程序员节,动态sql,mybaits,源码分析)