MyBatis源码通~SqlNode

SqlNode

每个 XML Node 会解析成对应的 SQL Node 对象。

public interface SqlNode {
 //将各Sql片段合并到DynamicContext中,拼接称为完整的SQL
  boolean apply(DynamicContext context);
}
  • apply方法会根据传入的参数context,参数解析该SqlNode所记录的SQL片段,并调用DynamicContext.appendSql()方法将解析后的SQL片段追加到DynamicContext.的sqlBuilder中保存。
  • 当SQL节点下的所有SqlNode完成解析后,可以通过DynamicContext.getSql()获取一条完成的SQL语句。
    在这里插入图片描述

0、创建SqlSource过程中获取SQL

//☆☆--RawSqlSource
public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {
   this(configuration, getSql(configuration, rootSqlNode), parameterType);
}

  /**
   * 通过遍历所有的SqlNode,获取sql
   */
private static String getSql(Configuration configuration, SqlNode rootSqlNode) {
    DynamicContext context = new DynamicContext(configuration, null);
    //rootSqlNode为MixedSqlNode
    rootSqlNode.apply(context);
    return context.getSql();
}
  • rootSqlNode.apply(context)开始解析MixedSqlNode中记录的SQL片段。
//☆☆--MixedSqlNode
public class MixedSqlNode implements SqlNode {
//记录sql节点中的所有SQL片段
 private final List<SqlNode> contents;

 public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
 }

  @Override
  public boolean apply(DynamicContext context) {
    //NOTE: 循环调用contents集合中的所有SqlNode对象的apply方法
    contents.forEach(node -> node.apply(context));
    return true;
  }
}
  • 通过解析sql节点得到的MixedSqlNode结构如下:
    在这里插入图片描述
  • 如下的sql配置构建的MixedSqlNode:
<select id="testSelect" resultMap="selectAuthor">
	SELECT
	id, username, password, email, bio, favourite_section
	FROM author
	id = 101
    <where>
        <if test="username != null">
			AND username = #{username}
        </if>
    </where>
</select>

在这里插入图片描述

1、StaticTextSqlNode

最简单的SqlNode,功能仅仅就是将自身记录的text拼接到context上下文中。

//StaticTextSqlNode
public boolean apply(DynamicContext context) {
    context.appendSql(text);
    return true;
}

2、TextSqlNode

  1. 表示包含 “${}” 占位符的动态SQL节点。
  2. TextSqlNode.apply()方法会使用GenericTokenParser解析“${}”占位符,并直接替换成传入的实际参数值。
  3. 实际参数值获取逻辑在内部BindingTokenParser.handleToken中。

3、IfSqlNode

if标签平常用的最多,在处理对应节点逻辑时,其主要工作就是通过Ognl表达式和传入的参数进行判断,看传入的参数值是否有满足if test里的表达式,满足将SQL片段合并到context上下文中。若不满足test则过滤掉这一部分SQL片段,不添加到context中。

4、WhereSqlNode、SetSqlNode

<where /> 标签的 SqlNode 实现类,继承至WhereSqlNode。
<set /> 标签的 SqlNode 实现类,继承至SetSqlNode。

  • WhereSqlNode会传入prefix=WHEREprefixesToOverride=["AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t"]
  • SetSqlNode会传入prefix=WHEREprefixesToOverride=[“,”]
  • 所以说trim和where、set是同一个套路

5、TrimSqlNode

<trim /> 标签的 SqlNode 实现类

 private final String prefix;
  private final String suffix;
  /**
   * 需要被删除的前缀
   */
  private final List<String> prefixesToOverride;
  /**
   * 需要删除的后缀
   */
  private final List<String> suffixesToOverride;

6、ForEachSqlNode

<foreach /> 标签的 SqlNode 实现类

7、VarDeclSqlNode

<bind /> 标签的 SqlNode 实现类,只要通过

public boolean apply(DynamicContext context) {
    //NOTE: OGNL表达式
    final Object value = OgnlCache.getValue(expression, context.getBindings());
    //NOTE: 绑定到上下文(记录到ContextMap中)
    context.bind(name, value);
    return true;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只打杂的码农

你的鼓励是对我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值