关于前端:聊聊Mybatis的动态Sql之这三个SqlNode同样重要

2次阅读

共计 2818 个字符,预计需要花费 8 分钟才能阅读完成。

聊聊 Mybatis 的动静 Sql 之这三个 SqlNode 同样重要
ForEachSqlNode

ForEachSqlNode 是解析出 <foreach> 的对象,

@Override
  public boolean apply(DynamicContext context) {Map<String, Object> bindings = context.getBindings();
    final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings,
      Optional.ofNullable(nullable).orElseGet(configuration::isNullableOnForEach));
    if (iterable == null || !iterable.iterator().hasNext()) {return true;}
    boolean first = true;
    applyOpen(context);
    int i = 0;
    for (Object o : iterable) {
      DynamicContext oldContext = context;
      if (first || separator == null) {context = new PrefixedContext(context, "");
      } else {context = new PrefixedContext(context, separator);
      }
      int uniqueNumber = context.getUniqueNumber();
      // Issue #709
      if (o instanceof Map.Entry) {@SuppressWarnings("unchecked")
        Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;
        applyIndex(context, mapEntry.getKey(), uniqueNumber);
        applyItem(context, mapEntry.getValue(), uniqueNumber);
      } else {applyIndex(context, i, uniqueNumber);
        applyItem(context, o, uniqueNumber);
      }
      contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));
      if (first) {first = !((PrefixedContext) context).isPrefixApplied();}
      context = oldContext;
      i++;
    }
    applyClose(context);
    context.getBindings().remove(item);
    context.getBindings().remove(index);
    return true;
  }

解析 <foreach> 的 collection 属性的表达式,失去汇合,增加 open 属性的字符串
遍历汇合,构建 PrefixedContext 对象,如果是 Map 类型,将 key value 保留到 PrefixedContext 对象中,不是的话就将汇合元素下标记和汇合元素保留到 PrefixedContext 对象中,调用 SqlNode 的 apply()办法,解决 #{}占位符
调用 applyClose()办法增加 close 属性后缀
删除 DynamicContext 对象中的 index 和 item

VarDeclSqlNode

VarDeclSqlNode 是解析 <bind> 标签的类

public class VarDeclSqlNode implements SqlNode {

  private final String name;
  private final String expression;

  public VarDeclSqlNode(String var, String exp) {
    name = var;
    expression = exp;
  }

  @Override
  public boolean apply(DynamicContext context) {final Object value = OgnlCache.getValue(expression, context.getBindings());
    context.bind(name, value);
    return true;
  }

}

name 保留了 bind 标签的 name 属性值,value 保留 bind 标签的 value 属性值,apply()办法中利用 OGNL 解析表达式的值,而后把 name 和 value 绑定到 DynamicContext 中,这样就能依据 name 获取到 value 值了。
ChooseSqlNode

ChooseSqlNode 是解析出 choose 标签的类

public class ChooseSqlNode implements SqlNode {
  private final SqlNode defaultSqlNode;
  private final List<SqlNode> ifSqlNodes;

  public ChooseSqlNode(List<SqlNode> ifSqlNodes, SqlNode defaultSqlNode) {
    this.ifSqlNodes = ifSqlNodes;
    this.defaultSqlNode = defaultSqlNode;
  }

  @Override
  public boolean apply(DynamicContext context) {for (SqlNode sqlNode : ifSqlNodes) {if (sqlNode.apply(context)) {return true;}
    }
    if (defaultSqlNode != null) {defaultSqlNode.apply(context);
      return true;
    }
    return false;
  }
}

它的 apply()办法也比较简单:遍历所有 ifSqlNodes,也是 when 标签的对象信息,调用各自的 apply()办法,返回胜利示意 when 条件成立,就返回 true,defaultSqlNode 不为空也是 true,其余为 false
总结

这篇文章次要讲了解析 foreach 标签的类 ForEachSqlNode、解析 <bind> 标签的 VarDeclSqlNode 类和解析 choose 标签的 ChooseSqlNode 类,同时介绍这三个类的 apply()办法的实现,这三个类都是 SqlNode 的实现类,都是对 xml 文件中的标签解析成的对象,这些 SqlNode 对象会被解析解决成 SqlSource 接口和它的实现类,供数据库执行,下篇文章咱们将介绍 SqlSource 接口和它的实现类

对文章中内容感兴趣的小伙伴能够搜寻微信公众号:敲代码的老贾,支付相应材料

正文完
 0