1. 程式人生 > >Java-ORM-MyBatis:MyBatis 3 動態 SQL

Java-ORM-MyBatis:MyBatis 3 動態 SQL

ylbtech-Java-ORM-MyBatis:MyBatis 3 動態 SQL

 

1.返回頂部
1、

動態 SQL

MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。

雖然在以前使用動態 SQL 並非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 對映語句中的強大的動態 SQL 語言得以改進這種情形。

動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

if

       

動態 SQL 通常要做的事情是根據條件包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if
test="title != null"> AND title like #{title} </if> </select>
       

這條語句提供了一種可選的查詢文字功能。如果沒有傳入“title”,那麼所有處於“ACTIVE”狀態的BLOG都會返回;反之若傳入了“title”,那麼就會對“title”一列進行模糊查詢並返回 BLOG 結果(細心的讀者可能會發現,“title”引數值是可以包含一些掩碼或萬用字元的)。

       

如果希望通過“title”和“author”兩個引數進行可選搜尋該怎麼辦呢?首先,改變語句的名稱讓它更具實際意義;然後只要加入另一個條件即可

<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>

choose, when, otherwise

       

有時我們不想應用到所有的條件語句,而只想從中擇其一項。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。

       

還是上面的例子,但是這次變為提供了“title”就按“title”查詢,提供了“author”就按“author”查詢的情形,若兩者都沒有提供,就返回所有符合條件的 BLOG(實際情況可能是由管理員按一定策略選出 BLOG 列表,而不是返回大量無意義的隨機結果)。

<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>

trim, where, set

前面幾個例子已經合宜地解決了一個臭名昭著的動態 SQL 問題。現在回到“if”示例,這次我們將“ACTIVE = 1”也設定成動態的條件,看看會發生什麼。

<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>
       

如果這些條件沒有一個能匹配上會發生什麼?最終這條 SQL 會變成這樣:

SELECT * FROM BLOG
WHERE

這會導致查詢失敗。如果僅僅第二個條件匹配又會怎樣?這條 SQL 最終會是這樣:

SELECT * FROM BLOG
WHERE 
AND title like someTitle
       

這個查詢也會失敗。這個問題不能簡單地用條件句式來解決,如果你也曾經被迫這樣寫過,那麼你很可能從此以後都不會再寫出這種語句了。

       

MyBatis 有一個簡單的處理,這在 90% 的情況下都會有用。而在不能使用的地方,你可以自定義處理方式來令其正常工作。一處簡單的修改就能達到目的:

<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
       

where 元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭為“AND”或“OR”,where 元素也會將它們去除。

       

如果 where 元素沒有按正常套路出牌,我們可以通過自定義 trim 元素來定製 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:

<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
       

prefixOverrides 屬性會忽略通過管道分隔的文字序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內容,並且插入 prefix 屬性中指定的內容。

       

類似的用於動態更新語句的解決方案叫做 setset 元素可以用於動態包含需要更新的列,而捨去其它的。比如:

<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>
       

這裡,set 元素會動態前置 SET 關鍵字,同時也會刪掉無關的逗號,因為用了條件語句之後很可能就會在生成的 SQL 語句的後面留下這些逗號。(譯者注:因為用的是“if”元素,若最後一個“if”沒有匹配上而前面的匹配上,SQL 語句的最後就會有一個逗號遺留)

       

若你對 set 元素等價的自定義 trim 元素的程式碼感興趣,那這就是它的真面目:

<trim prefix="SET" suffixOverrides=","> ... </trim>
       

注意這裡我們刪去的是字尾值,同時添加了字首值。

foreach

       

動態 SQL 的另外一個常用的操作需求是對一個集合進行遍歷,通常是在構建 IN 條件語句的時候。比如:

<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
       

foreach 元素的功能非常強大,它允許你指定一個集合,宣告可以在元素體內使用的集合項(item)和索引(index)變數。它也允許你指定開頭與結尾的字串以及在迭代結果之間放置分隔符。這個元素是很智慧的,因此它不會偶然地附加多餘的分隔符。

       

注意 你可以將任何可迭代物件(如 List、Set 等)、Map 物件或者陣列物件傳遞給 foreach 作為集合引數。當使用可迭代物件或者陣列時,index 是當前迭代的次數,item 的值是本次迭代獲取的元素。當使用 Map 物件(或者 Map.Entry 物件的集合)時,index 是鍵,item 是值。

       

到此我們已經完成了涉及 XML 配置檔案和 XML 對映檔案的討論。下一章將詳細探討 Java API,這樣就能提高已建立的對映檔案的利用效率。

bind

bind 元素可以從 OGNL 表示式中建立一個變數並將其繫結到上下文。比如:

<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
     

多資料庫支援

       

一個配置了“_databaseId”變數的 databaseIdProvider 可用於動態程式碼中,這樣就可以根據不同的資料庫廠商構建特定的語句。比如下面的例子:

<insert id="insert"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> <if test="_databaseId == 'oracle'"> select seq_users.nextval from dual </if> <if test="_databaseId == 'db2'"> select nextval for seq_users from sysibm.sysdummy1" </if> </selectKey> insert into users values (#{id}, #{name}) </insert>

動態 SQL 中的可插拔指令碼語言

       

MyBatis 從 3.2 開始支援可插拔指令碼語言,這允許你插入一種指令碼語言驅動,並基於這種語言來編寫動態 SQL 查詢語句

       

可以通過實現以下介面來插入一種語言

public interface LanguageDriver { ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql); SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType); SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType); }
       

一旦設定了自定義語言驅動,你就可以在 mybatis-config.xml 檔案中將它設定為預設語言:

<typeAliases>
  <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/> </typeAliases> <settings> <setting name="defaultScriptingLanguage" value="myLanguage"/> </settings>

除了設定預設語言,你也可以針對特殊的語句指定特定語言,可以通過如下的 lang 屬性來完成:

<select id="selectBlog" lang="myLanguage"> SELECT * FROM BLOG </select>
       

或者,如果你使用的是對映器介面類,在抽象方法上加上 @Lang 註解即可:

public interface Mapper { @Lang(MyLanguageDriver.class) @Select("SELECT * FROM BLOG") List<Blog> selectBlog(); }

注意 可以將 Apache Velocity 作為動態語言來使用,更多細節請參考 MyBatis-Velocity 專案。

       

你前面看到的所有 xml 標籤都是由預設 MyBatis 語言提供的,而它由別名為 xml 的語言驅動器 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver 所提供。

2、
2.返回頂部
 
3.返回頂部
 
4.返回頂部
 
5.返回頂部
1、 http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html 2、  
6.返回頂部
 
warn 作者:ylbtech
出處:http://ylbtech.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。