Mybatis動態SQL常用標籤
動態 SQL
MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。
MyBatis 提供了可以被用在任意 SQL 對映語句中的強大的動態 SQL 語言得以改進這種情形。
動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
一、if 標籤
動態 SQL 通常要做的事情是根據條件包含 where 子句的一部分
拼接條件的時候,加了一個恆等條件(1=1),避免多出and
public List<User> getUserBylike(@Param("username") String username, @Param("state") Integer state); <select id="getUserBylike" resultType="cn.jq.mybatis.model.User"> select * from t_user where 1=1 <if test="username != null and username != ''"> and username like #{username} </if> <if test="state != null and state >= 0"> and state like #{state} </if> </select>
List<User> userList = userMapper.getUserBylike("%a%",1);
select * from t_user where 1=1 and username like ? and state like ?
強調一下:
1)在介面中最好加@Param註解,以防止以下異常ReflectionException: There is no getter for property named...
2)if標籤裡的test屬性裡是用的OGNL表示式,這是apache下的一個標籤,用法類似jstl,但有些小差別,具體的內容可以在ognl官網上查詢,有些特殊符號在xml檔案裡不能直接使用,可以在w3cschool裡查
二、where標籤
上面恆等條件(1=1),避免多出and ,但是,Mybatis提供了一種解決辦法就是where標籤,
where 元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭為“AND”或“OR”,where 元素也會將它們去除。
<select id="getUserBylike" resultType="cn.jq.mybatis.model.User">
select * from t_user
<where>
<if test="username != null and username != ''">
and username like concat('%',concat(#{username},'%'))
</if>
<if test="state != null and state >= 0">
and state like #{state}
</if>
</where>
</select>
List<User> userList = userMapper.getUserBylike("a",1);
select * from t_user WHERE username like concat('%',concat(?,'%')) and state like ?
注意:where標籤只能去掉語句的開頭為“AND”或“OR” ,並不能去掉後面的,如果我們非要寫在後面,這時可以通過自定義 trim 元素來定製 where 元素的功能。
三、 trim 標籤(自定義 trim 元素)
四個屬性:
prefix:加字首
prefixOverrides:移除所有指定在 prefixOverrides 屬性中的內容,並且插入 prefix 屬性中指定的內容
suffix:加字尾
suffixOverrides:如果發現字串後有某個字尾,把它幹掉
<select id="getUserBylike" resultType="cn.jq.mybatis.model.User">
select * from t_user
<trim prefix="where" suffixOverrides="AND|OR">
<if test="username != null and username != ''">
username like #{username} and
</if>
<if test="state != null and state >= 0">
state like #{state} and
</if>
</trim>
</select>
四、set標籤
用於動態更新語句的解決方案叫做 set。set 元素可以用於動態包含需要更新的列,而捨去其它的。
public boolean updateUser(User user);
<update id="updateUser" parameterType="cn.jq.mybatis.model.User">
update t_user
<set>
<if test="username != null and username != ''">
username=#{username},
</if>
<if test="pazzword != null and pazzword != ''">
pazzword=#{pazzword},
</if>
<if test="state != null and state != ''">
state=#{state},
</if>
<if test="regDate != null">
reg_date=#{regDate},
</if>
</set>
where id=#{id}
</update>
這裡,set 元素會動態前置 SET 關鍵字,同時也會刪掉無關的逗號,因為用了條件語句之後很可能就會在生成的 SQL 語句的後面留下這些逗號。(譯者注:因為用的是“if”元素,若最後一個“if”沒有匹配上而前面的匹配上,SQL 語句的最後就會有一個逗號遺留)
若你對 set 元素等價的自定義 trim 元素的程式碼感興趣,那這就是它的真面目:
<update id="updateUser" parameterType="cn.jq.mybatis.model.User">
update t_user
<trim prefix="SET" suffixOverrides=",">
<if test="username != null and username != ''">
username=#{username},
</if>
<if test="pazzword != null and pazzword != ''">
pazzword=#{pazzword},
</if>
<if test="state != null and state != ''">
state=#{state},
</if>
<if test="regDate != null">
reg_date=#{regDate},
</if>
</trim>
where id=#{id}
</update>
五、choose (when, otherwise)標籤
有時我們不想應用到所有的條件語句,而只想從中擇其一項。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch...case,從上到下匹配,找到匹配的條件,就結束匹配其他的!
<select id="getUserBylike" resultType="cn.jq.mybatis.model.User">
select * from t_user where
<choose>
<when test="username != null and username != ''">
username like #{username}
</when>
<when test="state != null and state >= 0">
state like #{state}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>
六、foreach標籤
動態 SQL 的另外一個常用的操作需求是對一個集合進行遍歷,通常是在構建 IN 條件語句的時候
//通過一組id值查詢對應的user
public List<User> selectUserByIds(@Param("ids") int[] ids);
<select id="selectUserByIds" resultType="cn.jq.mybatis.model.User">
select * from t_user where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
int[] ids = new int[] {1,2};
List<User> userList = userMapper.selectUserByIds(ids);
System.out.println(Arrays.asList(userList));
----
select * from t_user where id in ( ? , ? )
collection="ids" : 介面上傳過來的數值或list集合或者map集合都可以
item="id" :設定遍歷集合或數組裡的每一個值的迭代變數
separator="," : 因為要構造出 (1,2,3)這種樣子的字串,設定中間的分隔符
open="(" : 因為要構造出 (1,2,3)這種樣子的字串,設定字首的符號(
close=")": 因為要構造出 (1,2,3)這種樣子的字串,設計結尾的字尾)
index: 瞭解,陣列或list集合的時候,設定索引變數,如果是Map集合就是map的key的迭代變數
foreach 元素的功能非常強大, 對於不同資料庫之間的批量操作也是經常使用。
七、bind標籤(瞭解)
bind 元素可以從 OGNL 表示式中建立一個變數並將其繫結到上下文
上面例子中的模糊查詢 傳參,使用bind元素 拼接 % 號, 注意不能傳null值
<select id="getUserBylike" resultType="cn.jq.mybatis.model.User">
<bind name="new_username" value="'%'+username+'%'"/>
select * from t_user where
<choose>
<when test="username != null and username != ''">
username like #{new_username}
</when>
<when test="state != null and state >= 0">
state like #{state}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>