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;
  }
}

總結

這篇文章從組合模式的角度分析瞭Mybatis動態sql的部分,SqlNode是組合模式的Component接口,MixedSqlNode是組合模式的Composite角色,還有其他的SqlNode的實現類TextSqlNode、TrimSqlNode、IfSqlNode、StaticTextSqlNode,它們是解析不同的標簽,TextSqlNode解析包含${}的動態sql片段,TrimSqlNode類解析trim標簽,IfSqlNode是解析出if 標簽、when標簽的類,StaticTextSqlNode是非動態的sql片段

到此這篇關於Mybatis的動態Sql組合模式詳情的文章就介紹到這瞭,更多相關Mybatis 組合模式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: