mybatis 的動態SQL使用

動態 SQLjava

動態 SQL 是mybatis一個很強大的特性,咱們常常會由於不一樣的條件去拼接sql,一不當心可能就會少了個空格,或是列名後面多了個逗號。利用動態sql能夠很靈活的去爲咱們拼接sql,且相對簡潔清晰。sql

這裏咱們主要來了解下面幾個元素:數組

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

1、if

咱們先看一下語法mybatis

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    where is_locked = 1
    <if test="loginname != null">
        and loginname like #{loginname}
    </if>
</select>

test 裏面是對條件的判斷,若裏面爲 true 的話,便會加上 if 元素裏的內容。如上面的loginname不爲空的話,sql語句就會是
select * from upms_user where is_locked = 1 and loginname like #{loginname}ide

test 裏面的 與 和 或 不能用 &&||,而是要使用 andorcode

test 屬性值是不能包含 '<' 字符的, 因此判斷大小不能用 <<=,用 ltlte 代替。>>= 雖然能夠用,但規範起見,最好也用 gtgte 代替xml

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    where is_locked = 1
    <if test="upmsUser.age gte 10 and upmsUser.age lt 20">
        <if test="loginname != null and loginname != '' ">
            and loginname like #{loginname}
        </if>
    </if>
</select>

2、choose (when, otherwise)

有時候咱們只想應用多個條件語句中的一個,咱們就要用到 choose (when, otherwise) 了。它與 java 中的 if...else if...elseswitch 很像。對象

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    where is_locked = 1
    <choose>
        <when test="loginname != null and loginname != '' ">
            and loginname like #{loginname}
        </when>
        <when test="upmsUser != null and upmsUser.realname != '' ">
            and realname like #{upmsUser.realname}
        </when>
        <otherwise>
            and phone is not null
        </otherwise>
    </choose>
</select>

test屬性值的語法和 if 元素的是同樣的索引

3、trim (where, set)

一、where

這裏咱們先回到 if 的第一個例子,假如把 is_locked 字段也設爲動態的字符串

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    where
    <if test="locked != null">
        is_locked = #{locked}
    </if>
    <if test="loginname != null and loginname != '' ">
        and loginname like #{loginname}
    </if>
</select>

若是兩個 if 的條件都成立,這時是沒有問題的,但有兩個狀況下會出問題。

  1. 若是兩個 if 都不成立,sql 語句就會變成
    select * from upms_user where (多了一個where)
  2. 若是 locked 爲 null,然後面的 if 成立,sql 語句就會變成
    select * from upms_user where and loginname like #{loginname} (多了一個and)

這裏其實咱們能夠在 where 後面加上一個 1=1,但 mabatis 給了咱們一個更好的解決方法

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    <where>
        <if test="locked != null">
            is_locked = #{locked}
        </if>
        <if test="loginname != null and loginname != '' ">
            and loginname like #{loginname}
        </if>
    </where>
</select>

使用 where 元素,它會在沒有條件成立時去掉where,在有條件成立的時候檢查語句的開頭,並去掉多餘的 and 或是 or

二、set

一樣的道理,咱們在更新數據時使用 if 動態更新語句也可能會出現問題。這裏能夠使用 set 元素

<update id="updateUser">
  update user
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="phone != null">phone=#{phone}</if>
    </set>
  where id=#{id}
</update>

它會刪除set語句後面可能會多出來的逗號

三、trim

有時候咱們在其餘地方可能也須要相似的功能,去除某些語句開頭或結尾多出來的符號或是鏈接詞。這時候咱們能夠使用 trim 去定製某些功能

<!-- prefix:前綴詞  prefixOverrides:語句前多餘要去除的內容   suffixOverrides:語句後多餘要去除的內容 -->
<trim prefix="" prefixOverrides="" suffixOverrides="">
  ...
</trim>

這裏咱們能夠自定義與 where 和 set 元素等價的 trim 元素

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

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

4、foreach

動態 SQL 的另一個經常使用的操做需求是對一個集合進行遍歷,一般是在構建 IN 條件語句的時候

<select id="selectUser" resultMap="upmsUser">
    select * from upms_user
    where user_id in
    <foreach item="item" index="index" collection="userIdList"
       open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

collection 表示要遍歷的集合或數組,item 表示當前遍歷的對象,index 表示當前遍歷的序號或鍵,在元素體內使用的集合項(item)和索引(index)變量。
open、close、separator 能夠指定開頭與結尾的字符串以及在迭代結果之間放置分隔符

你能夠將任何可迭代對象(如 List、Set 等)、Map 對象或者數組對象傳遞給 foreach 做爲集合參數。當使用可迭代對象或者數組時,index 是當前迭代的次數,item 的值是本次迭代獲取的元素。當使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值

5、bind

bind 元素能夠從 OGNL 表達式中建立一個變量並將其綁定到上下文

<select id="selectUser" resultMap="User">
  <bind name="pattern" value="'%' + user.getLoginname() + '%'" />
  SELECT * FROM upms_user
  WHERE loginname LIKE #{pattern}
</select>
相關文章
相關標籤/搜索