Mybatis SqlNode源码解析

本文深入解析Mybatis的ForeachSqlNode和TrimSqlNode。Foreach标签用于处理列表或数组,生成如(101,102,103)的SQL片段,而Trim标签则用于添加或删除SQL语句的前缀和后缀,如转换为'where'开头的条件。文章通过源码分析这两个关键节点的工作原理。" 132211176,8753399,JavaScript实现最低成本字符串转换算法,"['JavaScript', '算法', '开发语言']
摘要由CSDN通过智能技术生成

1.ForEachSqlNode

mybatis的foreach标签可以将列表、数组中的元素拼接起来,中间可以指定分隔符separator

<select id="getByUserId" resultMap="BaseMap">
    select <include refid="BaseFields"></include>
    from user
    <where>
      user_id in
      <foreach collection="userIdList" item="userId" open="(" separator="," close=")">
        #{userId}
      </foreach>
    </where>
  </select>

上面这段select sql代码使用了foreach标签,传入了一个userIdList的列表,首先会转化为一个ForeachSqlNode对象,经过处理后foreach标签里面的代码会解析成 (假设userIdList=[101,102,103])

(#{__frch_userId_0}, #{__frch_userId_1},#{__frch_userId_2}) , 后续预处理值替换后就会变成 (101,102,103)

下面是具体的ForEachSqlNode的解析过程源码:

public class ForEachSqlNode implements SqlNode {
  public static final String ITEM_PREFIX = "__frch_";

  // 表达式值获取器
  private final ExpressionEvaluator evaluator;
  // collection userIdList
  private final String collectionExpression;
  private final SqlNode contents;
  // open值 (
  private final String open;
  // close值 )
  private final String close;
  // separator分隔符值 ,
  private final String separator;
  // item值 userId
  private final String item;
  // index值 null
  private final String index;
  // mybatis配置信息
  private final Configuration configuration;

  public ForEachSqlNode(Configuration configuration, SqlNode contents, String collectionExpression, String index, String item, String open, String close, String separator) {
    this.evaluator = new ExpressionEvaluator();
    this.collectionExpression = collectionExpression;
    this.contents = contents;
    this.open = open;
    this.close = close;
    this.separator = separator;
    this.index = index;
    this.item = item;
    this.configuration = configuration;
  }

  @Override
  public boolean apply(DynamicContext context) {
    Map<String, Object> bindings = context.getBindings();
    // 迭代器
    final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings);
    if (!iterable.iterator().hasNext()) {
      return true;
    }
    boolean first = true;
    // 添加open值
    applyOpen(context);
    int i = 0;
    for (Object o : iterable) {
      DynamicContext oldContext = context;
      // 第一次循环first为true,使用new PrefixedContext(context, "")构建context,因为第一个元素之前不用添加分隔符
      // 第一次循环完毕后first为false,使用new PrefixedContext(context, separator)构建,之后先添加分隔符再添加sql值
      if (first || separator == null) {
        context = new PrefixedContext(context, "");
      } else {
        context = new PrefixedContext(context, separator);
      }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值