最近在學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的值。