共计 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 接口和它的实现类
对文章中内容感兴趣的小伙伴能够搜寻微信公众号:敲代码的老贾,支付相应材料