zoukankan      html  css  js  c++  java
  • Mybatis之trim标签的理解

    转自:https://www.cnblogs.com/westward/p/6706570.html

    最近在学Mybatis,在学到动态sql的trim标签时,很迷惑。不知所以然。看别人的博客和论坛里的解释,太宽泛,还是不能理解:

    trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where元素的功能。

    例1:

    复制代码
     1 <select id="selectUsersTrim" resultMap="resultListUsers" parameterType="Users">
     2       select * from users
     3       <trim prefix="where" prefixOverrides="and">
     4           <if test="name!=null">
     5               name=#{name}
     6           </if>
     7           <if test="address!=null">
     8                and address=#{address}
     9           </if>
    10       </trim>    
    11   </select>
    复制代码

    可以看到后台打印的sql:

    例2:

    复制代码
     1   <select id="selectUsersTrim" resultMap="resultListUsers" parameterType="Users">
     2       select * from users
     3       <trim prefix="where" prefixOverrides="and">
     4           <if test="name!=null">
     5               or name=#{name}
     6           </if>
     7           <if test="address!=null">
     8                and address=#{address}
     9           </if>
    10       </trim>    
    11   </select>
    复制代码

    后台报错:

    怎么办呢?遇到问题,当然要想办法解决。灵光一闪,我不是把源代码绑定到了mybatis的jar上了吗?对,那就看源代码,源代码还能debug呢,更方便。

    trim标签的java方法调用栈轨迹:(只写出关键的几个)

    org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply()

    org.apache.ibatis.scripting.xmltags.TrimSqlNode.FilteredDynamicContext.applyAll()

    org.apache.ibatis.scripting.xmltags.TrimSqlNode.FilteredDynamicContext.applyPrefix()

    applyPrefix()的源代码:

    代码块1:

    复制代码
     1  private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
     2       if (!prefixApplied) {
     3         prefixApplied = true;
     4         if (prefixesToOverride != null) {
     5           for (String toRemove : prefixesToOverride) {
     6             if (trimmedUppercaseSql.startsWith(toRemove)) {
     7               sql.delete(0, toRemove.trim().length());
     8               break;
     9             }
    10           }
    11         }
    12         if (prefix != null) {
    13           sql.insert(0, " ");
    14           sql.insert(0, prefix);
    15         }
    16       }
    17     }
    复制代码
    prefixApplied的值:初始是false.从下面代码内部类TrimSqlNode.FilteredDynamicContext的构造器可以看出:
    代码块2:
    复制代码
    1 public FilteredDynamicContext(DynamicContext delegate) {
    2       super(configuration, null);
    3       this.delegate = delegate;
    4       this.prefixApplied = false;
    5       this.suffixApplied = false;
    6       this.sqlBuffer = new StringBuilder();
    7     }
    复制代码
    List集合类型prefixesToOverride :trim标签的属性prefixOverrides,
    String类型prefix:trim标签的属性prefix.
    trimmedUppercaseSql:trim标签的子标签里的sql语句.
    见下面代码:(TrimSqlNode的成员变量):
    代码块3:
    1   private String prefix;
    2   private String suffix;
    3   private List<String> prefixesToOverride;
    4   private List<String> suffixesToOverride;

    现在我们在回看代码块1,会发现整个方法的大致意思:当trim标签prefixOverrides属性不为空时,遍历prefixOverrides集合的值,并且用trim标签里第一个子标签(比如if标签)的sql的语句头去匹配prefixOverrides集合的元素值,一旦匹配成功,则将第一个子标签的sql语句匹配的元素删掉,继续向下运行,判断prefix属性是否有值,若有值,在将prefix的值放到第一个子标签的sql语句开头。

    所以,例2,将prefixOverrides的值改为 or  或者 and|or 就行了。 

    好吧,就是这样,可能是自己的语言表达能力不够水平,感觉还是看代码来的精确 :)

    最后在总结下吧:

    trim标签的prefixOverrides和prefix分两步骤:

    1.如果prefixOverrides有元素,拿元素去匹配 第一个子标签sql语句,若匹配上,就删掉sql语句的匹配部分,跳到2

    2.如果prefix有值,就在  第一个子标签sql语句 的最前面加上 prefix的值。

  • 相关阅读:
    找零钱「Usaco2006 Dec」
    才艺表演「Usaco2018 Open」
    潜入行动「JSOI2018」
    任务安排「SDOI2012」
    BZOJ2298: [HAOI2011]problem a
    JZOJ 5818
    JZOJ 3493
    JZOJ 3470
    JZOJ 5781
    JZOJ 5778
  • 原文地址:https://www.cnblogs.com/keyi/p/10276906.html
Copyright © 2011-2022 走看看