有幾年開發經驗的程序員應該都有暗罵過原生的SQL語句吧。因為他們不能一句就搞定一個業務,往往還要通過代碼來拼接相關的SQL語句。相信大家會理解SQL里面的永真(1=1),永假(1=2)的意義吧。所以mybatis動態SQL功能在筆者看來是最引吸人的。為了更好的區別XML映射文件上的SQL語句。mybatis把SQL語句分為四類。那么這個筆者已經在前面的章節里面講過了。但是我們在開發過程中常常用到的也就倆種:靜態和動態。
關於靜態和動態的定義,筆者是這樣子理解的——靜態SQL語句顯示就是里面沒有相關的羅輯。即是沒有#if之類的語活。反之則是動態SQL語句。而筆者感興趣是動態SQL部分。我們都知道在讀取XML映射文件信息的時候就會分析當前的SQL語句屬於哪一種類型。這部分工作就是放在源碼的XMLScriptBuilder類里面。
1 public SqlSource parseScriptNode() { 2 List<SqlNode> contents = parseDynamicTags(context); 3 MixedSqlNode rootSqlNode = new MixedSqlNode(contents); 4 SqlSource sqlSource = null; 5 if (isDynamic) { 6 sqlSource = new DynamicSqlSource(configuration, rootSqlNode); 7 } else { 8 sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); 9 } 10 return sqlSource; 11 }
看到了吧,是通過成員isDynamic的值來獲取相關類型的SQL語句類。DynamicSqlSource類從字面上來講就很容易看出來是屬於動態的。而下面便是靜態的。關鍵的部分還是在parseDynamicTags方法里面。
為了實現動態SQL語句的功能。mybatis設置幾個動態的節點。如if,choose 等。當然如果你們想要知道有幾個的話,最好跟筆者一樣子點開他相關的DTD文件。如下
<!ELEMENT select (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
我們可以看到include 、trim 、where 、set 、foreach 、choose 、if 、bind。各自的用法在官網上面有些詳細的說明。 大家可以去看看。相信大家看到這里心里應該有了一定的想法。為了實現動態SQL,那么mybatis一定會根據不同的節點來做不同的邏輯處理。這也是筆者為什么說——關鍵的部分還是在parseDynamicTags方法里面。因為parseDynamicTags方法是用於分析當前select或是delete等節點的SQL節點(即是SqlNode類)。可以說終於生成的SQL語句就是靠這若干個SqlNode類提供生成的。在前面幾章中我們有講到關於BoundSql類的作用。在這里就一下明白了。如下圖
通過parseDynamicTags方法分析出需要用到的若干個SqlNode類。並確定他是否是動態SQL語句。如果是,就創建DynamicSqlSource類。而DynamicSqlSource類會存放在MappedStatement類里面。當我們要通過BoundSql類來生成StatementHandler實例的時候,就會從通過MappedStatement類獲得對應的BoundSql類。而BoundSql類的getSql方法就會我們最終的落點。
其實筆者的內心是有一點小失望的。我本以為mybatis會一直實現自己的元素處理。當然這只是筆者內心的一點完美主義吧。正如官網上講的MyBatis 采用功能強大的基於 OGNL 的表達式來消除其他元素。所以我們可以源碼里面看到ognl的應用。
Map<Object, OgnlClassResolver> context = Ognl.createDefaultContext(root, new OgnlClassResolver());
對於ongl筆者就不想多說了。有興趣的讀者們可以自己去看一下。筆者建議還是去看一下吧。struts2框架里面也用到他了。
關於mybatis系列筆者就記錄到這里了。希望對大家有用。