Mybatis的动态Sql组合模式怎么实现

寻技术 JAVA编程 / 其他编程 2023年09月24日 73

今天小编给大家分享一下Mybatis的动态Sql组合模式怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    前言

    当同一类型的很多对象组成一个树结构的时候,可以考虑使用组合模式,组合模式涉及三个类:

    Component接口:定义树的各个节点的一些操作

    Left类:这个是树的叶子结点,实现Component接口,对于节点的管理它不去实现,只实现业务逻辑

    Composite类:这个是树的非叶子节点,实现Component接口,不但实现业务逻辑,同时会管理子节点,会有个Component接口的集合类来管理子节点

    Component角色

    SqlNode就是扮演组合模式中的Component角色,Sql标签会解析成SqlNode对象,

    public interface SqlNode {
      boolean apply(DynamicContext context);
    }

    Composite角色

    MixedSqlNode类扮演组合模式的Composite角色:

    它也是解析

    <otherwise>
    标签的类
    public class MixedSqlNode implements SqlNode {
      private final List<SqlNode> contents;
    
      public MixedSqlNode(List<SqlNode> contents) {
        this.contents = contents;
      }
    
      @Override
      public boolean apply(DynamicContext context) {
        contents.forEach(node -> node.apply(context));
        return true;
      }
    }

    它有个SqlNode的集合类,记录SqlNode对象,apply方法就是遍历集合,依次调用自己的apply()方法

    剩余其他SqlNode的实现类就充当组合模式的Left类了:

    Left类角色

    TextSqlNode

    TextSqlNode是包含${}的动态sql片段,它的apply()方法的实现:

      @Override
      public boolean apply(DynamicContext context) {
        GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
        context.appendSql(parser.parse(text));
        return true;
      }
      private GenericTokenParser createParser(TokenHandler handler) {
        return new GenericTokenParser("${", "}", handler);
      }

    创建GenericTokenParser解析器,然后解析包含${}的sql片段,解析后保存到DynamicContext中

    TrimSqlNode

    TrimSqlNode是解析出的trim标签的对象,trim标签可以去除sql的and、逗号或者拼接where关键字等,

      private final SqlNode contents;
      @Override
      public boolean apply(DynamicContext context) {
        FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
        boolean result = contents.apply(filteredDynamicContext);
        filteredDynamicContext.applyAll();
        return result;
      }

    先调用SqlNode 的apply方法 ,然后调用FilteredDynamicContext的applyAll()方法进行前后缀的处理,FilteredDynamicContext在DynamicContext包装了一层,利用了装饰者模式,除了DynamicContext的存储解析结果和参数功能外还能进行前后缀的处理

    IfSqlNode

    IfSqlNode是解析出if 标签、when标签的类,

    public class IfSqlNode implements SqlNode {
      private final ExpressionEvaluator evaluator;
      private final String test;
      private final SqlNode contents;
    
      public IfSqlNode(SqlNode contents, String test) {
        this.test = test;
        this.contents = contents;
        this.evaluator = new ExpressionEvaluator();
      }
    
      @Override
      public boolean apply(DynamicContext context) {
        if (evaluator.evaluateBoolean(test, context.getBindings())) {
          contents.apply(context);
          return true;
        }
        return false;
      }
    }

    ExpressionEvaluator是解析工具类,test记录了if标签的test表达式,apply()方法中ExpressionEvaluator工具类解析test表达式,返回true之后调用具体SqlNode的apply()方法

    StaticTextSqlNode

    StaticTextSqlNode是非动态的sql片段,apply()方法直接把sql片段追加到DynamicContext的sqlBuilder属性中

    public class StaticTextSqlNode implements SqlNode {
      private final String text;
    
      public StaticTextSqlNode(String text) {
        this.text = text;
      }
    
      @Override
      public boolean apply(DynamicContext context) {
        context.appendSql(text);
        return true;
      }
    }
    关闭

    用微信“扫一扫”