动态sql解析源码分析

概述

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

总体架构

在这里插入图片描述

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

DynamicSqlSource 动态解析

在这里插入图片描述
源码

 @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 语法树解析

脚本组成
在这里插入图片描述
在这里插入图片描述
eg:

<select id="getSqlNode" resultType="com.wfg.entity.ActivityEntity">
    select id , name from activity
    <where>

       <if test="list != null">
         and id in
         <foreach collection="list" separator="," close=")" open="(" item="item" index="index">
           #{item}
         </foreach>
         <if test="name != null">
           and name = #{name}
         </if>
       </if>
    </where>
  </select>

在这里插入图片描述
源代码:

org.apache.ibatis.scripting.xmltags.XMLScriptBuilder#parseDynamicTags
protected MixedSqlNode parseDynamicTags(XNode node) {
    List<SqlNode> 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:<if> <where> 等等
      } 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 形成一个递归操作;
解析流程图:
在这里插入图片描述

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

提前初始化一些处理器;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值