1. 程式人生 > >Mybatis 動態Sql語句《常用》

Mybatis 動態Sql語句《常用》

意義 rom 存在 問題 rri 也會 輸出 ray 便是

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

最常用的就是 if where foreach這幾個,一定要重點掌握.

名詞解析:OGNL表達式

OGNL,全稱為Object-Graph Navigation Language,它是一個功能強大的表達式語言,用來獲取和設置Java對象的屬性,它旨在提供一個更高的更抽象的層次來對Java對象圖進行導航。

OGNL表達式的基本單位是"導航鏈",一般導航鏈由如下幾個部分組成:

(1)屬性名稱(property)

(2)方法調用(method invoke)

(3)數組元素

所有的OGNL表達式都基於當前對象的上下文來完成求值運算,鏈的前面部分的結果將作為後面求值的上下文。例如:names[0].length()。


mybatis 的動態sql語句基於OGNL表達式的。可以方便的在 sql 語句中實現某些邏輯. 總體說來mybatis 動態SQL 語句主要有以下幾類:
  1. if 語句 (簡單的條件判斷)
  2. choose (when,otherwize) ,相當於java 語言中的 switch ,與 jstl 中的choose 很類似.
  3. trim

(對包含的內容加上 prefix,或者 suffix 等,前綴,後綴)
  4. where (主要是用來簡化sql語句中where條件判斷的,能智能的處理 and or ,不必擔心多余導致語法錯誤)
  5. set (主要用於更新時)
  6. foreach (在實現 mybatis in 語句查詢時特別有用)
下面分別介紹這幾種處理方式

1、mybatis if語句處理

技術分享圖片
<select id="dynamicIfTest" parameterType="Blog" resultType="Blog">
    select * from t_blog where 1 = 1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="content != null">
        and content = #{content}
    </if>
    <if test="owner != null">
        and owner = #{owner}
    </if>
</select>
技術分享圖片

解析

  如果你提供了title參數,那麽就要滿足title=#{title},同樣如果你提供了Content和Owner的時候,它們也需要滿足相應的條件,之後就是返回滿足這些條件的所有Blog,這是非常有用的一個功能。

  以往我們使用其他類型框架或者直接使用JDBC的時候, 如果我們要達到同樣的選擇效果的時候,我們就需要拼SQL語句,這是極其麻煩的,比起來,上述的動態SQL就要簡單多了。

2、choose (when,otherwize) ,相當於java 語言中的 switch ,與 jstl 中的choose 很類似

技術分享圖片
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
    select * from t_blog where 1 = 1 
    <choose>
        <when test="title != null">
            and title = #{title}
        </when>
        <when test="content != null">
            and content = #{content}
        </when>
        <otherwise>
            and owner = "owner1"
        </otherwise>
    </choose>
</select>
技術分享圖片

when元素表示當when中的條件滿足的時候就輸出其中的內容,跟JAVA中的switch效果差不多的是按照條件的順序,當when中有條件滿足的時候,就會跳出choose,即所有的when和otherwise條件中,只有一個會輸出,當所有的我很條件都不滿足的時候就輸出otherwise中的內容。所以上述語句的意思非常簡單,當title!=null的時候就輸出and titlte = #{title},不再往下判斷條件,當title為空且content!=null的時候就輸出and content = #{content},當所有條件都不滿足的時候就輸出otherwise中的內容。

3、trim (對包含的內容加上 prefix,或者 suffix 等,前綴,後綴)

技術分享圖片
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
    select * from t_blog 
    <trim prefix="where" prefixOverrides="and |or">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="content != null">
            and content = #{content}
        </if>
        <if test="owner != null">
            or owner = #{owner}
        </if>
    </trim>
</select>
技術分享圖片

trim元素的主要功能是可以在自己包含的內容前加上某些前綴也可以在其後加上某些後綴,與之對應的屬性是prefix和suffix;可以把包含內容的首部某些內容覆蓋,即忽略,也可以把尾部的某些內容覆蓋,對應的屬性是prefixOverrides和suffixOverrides;正因為trim有這樣的功能,所以我們也可以非常簡單的利用trim來代替where元素的功能。

trim標記是一個格式化的標記,可以完成set或者是where標記的功能,如下代碼:

技術分享圖片
select * from user 
<trim prefix="WHERE" prefixoverride="AND |OR">
    <if test="name != null and name.length()>0"> 
        AND name=#{name}
    </if>
    <if test="gender != null and gender.length()>0"> 
        AND gender=#{gender}
    </if>
</trim>
技術分享圖片

假如說name和gender的值都不為null的話打印的SQL為:select * from user where name = ‘xx‘ and gender = ‘xx‘

在紅色標記的地方是不存在第一個and的,上面兩個屬性的意思如下:

prefix:前綴      

prefixoverride:去掉第一個and或者是or

技術分享圖片
update user
<trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
    <if test="name != null and name.length()>0">
        name=#{name} ,
    </if>
    <if test="gender != null and gender.length()>0">
        gender=#{gender} ,  
    </if>
</trim>
技術分享圖片

假如說name和gender的值都不為null的話打印的SQL為:update user set name=‘xx‘ , gender=‘xx‘ where id=‘x‘

在紅色標記的地方不存在逗號,而且自動加了一個set前綴和where後綴,上面三個屬性的意義如下,其中prefix意義如上:

suffixoverride:去掉最後一個逗號(也可以是其他的標記,就像是上面前綴中的and一樣)

suffix:後綴

4、where (主要是用來簡化sql語句中where條件判斷的,能智能的處理 and or 條件)

技術分享圖片
<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
    select * from t_blog 
    <where>
        <if test="title != null">
            title = #{title}
        </if>
        <if test="content != null">
            and content = #{content}
        </if>
        <if test="owner != null">
            and owner = #{owner}
        </if>
    </where>
</select>
技術分享圖片

where元素的作用是會在寫入where元素的地方輸出一個where,另外一個好處是你不需要考慮where元素裏面的條件輸出是什麽樣子的,MyBatis會智能的幫你處理,如果所有的條件都不滿足那麽MyBatis就會查出所有的記錄,如果輸出後是and 開頭的,MyBatis會把第一個and忽略,當然如果是or開頭的,MyBatis也會把它忽略;此外,在where元素中你不需要考慮空格的問題,MyBatis會智能的幫你加上。像上述例子中,如果title=null, 而content != null,那麽輸出的整個語句會是select * from t_blog where content = #{content},而不是select * from t_blog where and content = #{content},因為MyBatis會智能的把首個and 或 or 給忽略。

5、set (主要用於更新時)

技術分享圖片
<update id="dynamicSetTest" parameterType="Blog">
    update t_blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="content != null">
            content = #{content},
        </if>
        <if test="owner != null">
            owner = #{owner}
        </if>
    </set>
    where id = #{id}
</update>
技術分享圖片

set元素主要是用在更新操作的時候,它的主要功能和where元素其實是差不多的,主要是在包含的語句前輸出一個set,然後如果包含的語句是以逗號結束的話將會把該逗號忽略,如果set包含的內容為空的話則會出錯。有了set元素我們就可以動態的更新那些修改了的字段。

6、foreach (在實現 mybatis in 語句查詢時特別有用)

foreach的主要用在構建in條件中,它可以在SQL語句中進行叠代一個集合。foreach元素的屬性主要有item,index,collection,open,separator,close。

(1)item表示集合中每一個元素進行叠代時的別名。

(2)index指定一個名字,用於表示在叠代過程中,每次叠代到位置。

(3)open表示該語句以什麽開始。

(4)separator表示在每次進行叠代之間以什麽符號作為分隔符。

(5)close表示以什麽結束。

在使用foreach的時候最關鍵的也是最容易出錯的就是collection屬性,該屬性是必須指定的,但是在不同情況下,該屬性的值是不一樣的,主要有一下3種情況:

(1)如果傳入的是單參數參數類型是一個List的時候,collection屬性值為list

(2)如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值為array

(3)如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map,實際上如果你在傳入參數的時候,在MyBatis裏面也是會把它封裝成一個Map的,map的key就是參數名,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map裏面的key。

6.1、單參數List的類型

<select id="dynamicForeachTest" resultType="com.mybatis.entity.User">
    select * from t_user where id in
    <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

上述collection的值為list,對應的Mapper是這樣的:

/**mybatis Foreach測試 */
public List<User> dynamicForeachTest(List<Integer> ids); 

測試代碼:

技術分享圖片
@Test
public void dynamicForeachTest() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(2);
    ids.add(6);
    List<User> userList = mapper.dynamicForeachTest(ids);
    for (User user : userList){
        System.out.println(user);
    }
    sqlSession.close();
}
技術分享圖片

6.2、數組類型的參數

<select id="dynamicForeach2Test" resultType="com.mybatis.entity.User">
    select * from t_user where id in
    <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

對應mapper:

public List<User> dynamicForeach2Test(int[] ids);  

測試代碼:

技術分享圖片
@Test
public void dynamicForeach2Test() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int[] ids = {1,2,6};
    List<User> userList = mapper.dynamicForeach2Test(ids);
    for (User user : userList){
        System.out.println(user);
    }
    sqlSession.close();
}
技術分享圖片

6.3、Map類型的參數

<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User">
    select * from t_user where username like ‘%${username}%‘ and id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

mapper 應該是這樣的接口:

/**mybatis Foreach測試 */
public List<User> dynamicForeach3Test(Map<String, Object> params); 

測試方法:

技術分享圖片
@Test
public void dynamicForeach3Test() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(2);
    ids.add(6);
    Map map =new HashMap();
    map.put("username", "小");
    map.put("ids", ids);
    List<User> userList = mapper.dynamicForeach3Test(map);
    System.out.println("------------------------");
    for (User user : userList){
        System.out.println(user);
    }
    sqlSession.close();
}
技術分享圖片

通過以上方法,就能完成一般的mybatis 的 動態SQL 語句.

Mybatis 動態Sql語句《常用》