Mybatis之trim標籤的理解

最近在學Mybatis,在學到動態sql的trim標籤時,很迷惑。不知因此然。看別人的博客和論壇裏的解釋,太寬泛,仍是不能理解:java

trim元素的主要功能是能夠在本身包含的內容前加上某些前綴,也能夠在其後加上某些後綴,與之對應的屬性是prefix和suffix;能夠把包含內容的首部某些內容覆蓋,即忽略,也能夠把尾部的某些內容覆蓋,對應的屬性是prefixOverrides和suffixOverrides;正由於trim有這樣的功能,因此咱們也能夠很是簡單的利用trim來代替where元素的功能。sql

 

例1:apache

 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:mybatis

 

 

例2:app

 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>

後臺報錯:ide

 

怎麼辦呢?遇到問題,固然要想辦法解決。靈光一閃,我不是把源代碼綁定到了mybatis的jar上了嗎?對,那就看源代碼,源代碼還能debug呢,更方便。ui

trim標籤的java方法調用棧軌跡:(只寫出關鍵的幾個)this

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

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

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的值。

相關文章
相關標籤/搜索