mybatis逻辑标签 浅析

mybatis逻辑标签

mybatis 有 9 大标签,如下图

标签

我们只针对其中 select|insert|update|delete 的子标签部分进行探索

简介

首先要上一道菜,来介绍我们本节分析的内容

    <select id="selectAll" resultType="com.aya.mapper.Blog" >
        select * from blog
        <if test="order=='id'">
            ORDER BY id
        </if>
    </select>

本节以最简单的 if 子标签来作为例子,来理清 子标签的加载和执行流程

加载

选自 XMLScriptBuilder

  protected MixedSqlNode parseDynamicTags(XNode node) {
    List<SqlNode> contents = new ArrayList<SqlNode>();
    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));
        }
      } 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);
  }

这段代码是mybatis加载本例select标签的核心部分

来源

xml 来源:

settings=>mapper=>解析mapper文件=>select 标签解析

代码来源:

new SqlSessionFactoryBuilder().build(inputStream);

工作

  1. 将子节点分为两个块,静态块和节点块
  2. 遍历每个块,这里分为静态块和节点块两种处理方式

静态块

 select * from blog

节点块

 <if test="order=='id'">
            ORDER BY id
</if>

静态块处理

最终变成:

contents.add(new StaticTextSqlNode(“select * from blog”));

节点块处理

handler.handleNode(child, contents);

这里就是比较重要的地方了,对于动态块,mybatis 是如何处理的呢?

我们这里nodeName是if ,那么就相当于 nodeHandlerMap.get(“if”).handleNode(child, contents);

接下来就去找到 nodeHandlerMap 是如何初始化的吧!!

在XMLScriptBuilder的构造中调用了函数 initNodeHandlerMap ,初始化所有条件节点的处理方式

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

按照本例,我们去 IfHandler.handlerNode 去看看做了什么

    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
      String test = nodeToHandle.getStringAttribute("test");
      IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
      targetContents.add(ifSqlNode);
    }
  1. parseDynamicTags 解析内容
  2. 将 IfSqlNode 设置内容和条件
  3. 添加 IfSqlNode

加载小结

这里得出结论,在加载过程中,添加了一个静态块,一个动态块
1. contents.add(new StaticTextSqlNode(data));
2. contents.add(new IfSqlNode(mixedSqlNode, test));

执行

选自 MixedSqlNode, 遍历 SqlNode 拼接为 sql 语句

 @Override
  public boolean apply(DynamicContext context) {
    for (SqlNode sqlNode : contents) {
      sqlNode.apply(context);
    }
    return true;
  }

来源

代码来源:

    sqlSession.selectList("com.aya.mapper.BlogMapper.selectAll", new HashMap<String,String>(){
                {
                    put("order","id");
                }
    });

工作

  1. 执行 StaticTextSqlNode.apply, sql 语句为: select * from blog
  2. 执行 IfSqlNode.apply 成功,执行子节点块 StaticTextSqlNode.apply select * from blog ORDER BY id

此时,sql 被动态构建完成,接下来由执行器去执行

总结

本文以一个简单的例子来阐述 子标签 的加载和执行.

  1. 在 settings 加载时加载为 XXHandler ,然后将 XXHandler 转换为 XXSqlNode,添加到content里面
  2. 在 SqlSession 执行的时候,执行 XXSqlNode 的 apply

标签处理器表:

标签处理器节点
trimTrimHandlerTrimSqlNode
whereWhereHandlerWhereSqlNode extends TrimSqlNode
setSetHandlerSetSqlNode extends TrimSqlNode
foreachForEachHandlerForEachSqlNode
ifIfHandlerIfSqlNode
chooseChooseHandlerChooseSqlNode
whenIfHandlerIfSqlNode
otherwiseOtherwiseHandlerMixedSqlNode
bindBindHandlerVarDeclSqlNode
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值