当前位置: 首页 > article >正文

Mybatis框架中的foreach标签解析

如果是foreachNode则会预填充很多的参数及SQL语句以及展开的参数信息。foreach标签的注册:

当出现foreach标签的时候则调用对应的处理函数:

private void initNodeHandlerMap() {
        nodeHandlerMap.put("if", new IfHandler());
        nodeHandlerMap.put("foreach", new ForeachHandler());
    }

处理函数初始化foreach节点配置属性:

        @Override
        public void handleNode(XNode var1, List<SqlNode> var2) {
            MixedSqlNode mixedSqlNode = new MixedSqlNode(parseDynamicTags(var1));
            String collection = var1.getStringAttribute("collection");
            String item = var1.getStringAttribute("item");
            String index = var1.getStringAttribute("index");
            String open = var1.getStringAttribute("open");
            String close = var1.getStringAttribute("close");
            String separator = var1.getStringAttribute("separator");
            ForEachSqlNode foreachSqlNode = new ForEachSqlNode(XMLScriptBuilder.this.configuration,mixedSqlNode, collection, index, item, open, close, separator);
            var2.add(foreachSqlNode);
        }

这样就完成foreach标签的初始化,当系统执行的时候就需要组装SQL语句信息,这里还是apply方法,其中参数为传入的上下文信息。执行的原理就是:

  1. 通过ognl计算器获取遍历的集合对象;
  2. 根据open,close配置属性在sql中填充值;
  3. 在解析参数过程中最重要的就是对填充的每个item如何赋值?这里通过将配置的index和item都传入到DynamicContext中,这里的DynamicContext作用类似于符号表,用于保存执行上下文的变量配置信息,其中item生成的临时变量格式为: "__frch_" + item + "_" + I,index值为map中的key或者遍历的次数。
  4. 系统通过这些上下文最终执行foreach标签中的对象,产生sql语句,执行完成后移除这些临时生成的上下文信息。

在第三步中,为了方便将产生的临时变量替换为用户定义的值,这里进行了替换:

 public void appendSql(String sql) {
            GenericTokenParser parser = new GenericTokenParser("#{", "}", (content) -> {
                String newContent = content.replaceFirst("^\\s*" + this.item + "(?![^.,:\\s])", ForEachSqlNode.itemizeItem(this.item, this.index));
                if (this.itemIndex != null && newContent.equals(content)) {
                    newContent = content.replaceFirst("^\\s*" + this.itemIndex + "(?![^.,:\\s])", ForEachSqlNode.itemizeItem(this.itemIndex, this.index));
                }

                return "#{" + newContent + "}";
            });
            this.delegate.appendSql(parser.parse(sql));
        }

因为用户上下文(符号表)更新了,所以这里相应进行了处理。

@Override
    public boolean apply(DynamicContext context) {
        Map<String, Object> bindings = context.bindingsAsMap();
        Iterable<?> iterable = ForEachSqlNode.this.evaluator.evaluateIterable(collectionExpression, bindings);
        if(!iterable.iterator().hasNext()) {
            return true;
        } else {
            boolean first = true;
            this.applyOpen(context);
            int i = 0;
            for(Object o:iterable) {
                if(!first && this.separator != null) {
                    context = new PrefixedContext(context, this.separator);
                } else {
                    context = new PrefixedContext(context, "");
                }
                int uniqueNumber = context.getUniqueNumber();
                if(o instanceof  Map.Entry) {
                    Map.Entry<Object, Object> entry = (Map.Entry)o;
					//这里将index和item都添加到符号表中
                    this.applyIndex(context, entry.getKey(), uniqueNumber);
                    this.applyItem(context, entry.getValue(), uniqueNumber);
                } else {
//这里将index和item都添加到符号表中
                    this.applyIndex(context, i, uniqueNumber);
                    this.applyItem(context, o, uniqueNumber);
                }
                this.contents.apply(new FilteredDynamicContext(this.configuration, context, this.index, this.item, uniqueNumber));
                if(first) {
                    first = !((PrefixedContext)context).isPrefixApplied();
                }
                context = ((PrefixedContext) context).delegate;
                ++i;
            }
            this.applyClose(context);
            context.getBindings().remove(this.item);
            context.getBindings().remove(this.index);
            return true;
        }
    }

http://www.kler.cn/a/526886.html

相关文章:

  • 深度学习的应用
  • 【AI】Deepseek本地部署探索,尝试联网搜索
  • thinkphp6+swoole使用rabbitMq队列
  • 大数据学习之Kafka消息队列、Spark分布式计算框架一
  • 渗透测试技法之口令安全
  • JxBrowser 7.41.7 版本发布啦!
  • 【4Day创客实践入门教程】Day2 探秘微控制器——单片机与MicroPython初步
  • SQL进阶实战技巧:如何分析浏览到下单各步骤转化率及流失用户数?
  • 【C++语言】卡码网语言基础课系列----7. 摆平积木
  • Learning Vue 读书笔记 Chapter 4
  • DDD - 领域事件_解耦微服务的关键
  • char和varchar的区别、varchar(?)中问号部分的含义、索引的作用
  • 使用Pygame制作“俄罗斯方块”游戏
  • Spring Boot项目如何使用MyBatis实现分页查询及其相关原理
  • AJAX案例——图片上传个人信息操作
  • C++中vector追加vector
  • elasticsearch的常见面试题?
  • 亚博microros小车-原生ubuntu支持系列:15 激光雷达巡逻
  • 机器学习7-全连接神经网络3-过拟合与超参数
  • 信号模块--simulink操作
  • [Effective C++]条款53-55 杂项讨论
  • Linux第104步_基于AP3216C之I2C实验
  • Python学习之旅:进阶阶段(七)数据结构-计数器(collections.Counter)
  • TCP编程
  • 【Linux】日志设计模式与实现
  • DeepSeek Janus-Pro:多模态AI模型的突破与创新