MyBatis的學習(四)——MyBatis動態SQL
一、動態SQL介紹
MyBatis 的強大特性之一便是它的動態 SQL。如果有使用 JDBC 或其他類似框架的經驗,就能體會到根據不同條件拼接 SQL 語句有多麼痛苦。拼接的時候要確保不能忘了必要的空格,還要注意省掉列名列表最後的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。
通常使用動態 SQL 不可能是獨立的一部分,MyBatis 當然使用一種強大的動態 SQL 語言來改進這種情形,這種語言可以被用在任意的 SQL 對映語句中。
動態 SQL 元素和使用 JSTL 或其他類似基於 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多的元素需要來了解。MyBatis 3 大大提升了它們,現在用不到原先一半的元素就可以了。MyBatis 採用功能強大的基於 OGNL
mybatis 的動態sql語句是基於OGNL表示式的。可以方便的在 sql 語句中實現某些邏輯. 總體說來mybatis 動態SQL 語句主要有以下幾類:
- if 語句 (簡單的條件判斷)
- choose (when,otherwise) ,相當於java 語言中的 switch ,與 jstl 中的choose 很類似.
- trim (對包含的內容加上 prefix,或者 suffix 等,字首,字尾)
- where (主要是用來簡化sql語句中where條件判斷的,能智慧的處理 and or ,不必擔心多餘導致語法錯誤)
- set (主要用於更新時)
- foreach (在實現 mybatis in 語句查詢時特別有用)
二、動態SQL的使用
首先建立資料庫和建立users表
建立users實體類:
package com.little.entity; public class Users { private Integer id; private String name; private String sex; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Users{" + "id=" + id + ", name='" + name + '\'' + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } }
①if+where元素
根據name和sex元素來查詢資料,如何name為空,sex不為空,根據sex來查詢,反之根據name來查詢,都為空就全查,都不為空就根據兩者的條件來查詢。
<select id="queryByNameAndSex" resultType="Users" parameterType="Users">
select * from users
<where>
<if test="name != null">
and name = #{name}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
這個“where”標籤會知道如果它包含的標籤中有返回值的話,它就插入一個‘where’。此外,如果標籤返回的內容是以AND 或OR 開頭的,則它會剔除掉。
②if+set語句
比如在進行更新的時候,使用到set語句,MyBatis也有對應的set元素
<update id="updateUsersById" parameterType="Users">
update users u
<set>
<if test="name != null and name != ''">
u.name = #{name},
</if>
<if test="sex != null and sex != ''">
u.sex = #{sex},
</if>
</set>
where id=#{id}
</update>
如果出現多餘逗號 會自動去掉
③choose(when,otherwise)
有時候,我們不想用到所有的查詢條件,只想選擇其中的一個,查詢條件有一個滿足即可,使用 choose 標籤可以解決此類問題,類似於 Java 的 switch 語句
<select id="selectUsersByChoose" resultType="Users" parameterType="Users">
select * from users
<where>
<choose>
<when test="id !='' and id != null">
id=#{id}
</when>
<when test="name !='' and name != null">
and name=#{name}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
這裡就是隻根據一個條件來進行查詢,按照順序進行
④trim
trim標記是一個格式化的標記,可以完成set或者是where標記的功能
用 trim 改寫上面的 if+where 語句
<select id="selectUsersByNameAndSex" resultType="users" parameterType="Users">
select * from users
<trim prefix="where" prefixOverrides="and | or">
<if test="name != null">
and name=#{name}
</if>
<if test="sex != null">
and sex=#{sex}
</if>
</trim>
</select>
prefix:字首
prefixoverride:去掉第一個and或者是or
用 trim 改寫上面的 if+set 語句
<!-- 根據 id 更新 user 表的資料 -->
<update id="updateUsersById" parameterType="Users">
update users u
<trim prefix="set" suffixOverrides=",">
<if test="name != null and name != ''">
u.name = #{name},
</if>
<if test="sex != null and sex != ''">
u.sex = #{sex},
</if>
</trim>
where id=#{id}
</update>
suffix:字尾
suffixoverride:去掉最後一個逗號(也可以是其他的標記,就像是上面字首中的and一樣)
⑤SQL片段
有時候可能某個 sql 語句我們用的特別多,為了增加程式碼的重用性,簡化程式碼,我們需要將這些程式碼抽取出來,然後使用時直接呼叫。
比如:假如我們需要經常根據使用者名稱和性別來進行聯合查詢,那麼我們就把這個程式碼抽取出來,如下:
<!-- 定義 sql 片段 -->
<sql id="selectUsersByNameAndSexSQL">
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
</sql>
引用SQL片段
<select id="selectUsersByNameAndSex" resultType="users"
parameterType="Users">
select * from users
<trim prefix="where" prefixOverrides="and | or">
<!-- 引用 sql 片段,如果refid 指定的不在本檔案中,那麼需要在前面加上 namespace -->
<include refid="selectUsersByNameAndSexSQL"></include>
<!-- 在這裡還可以引用其他的 sql 片段 -->
</trim>
</select>
注意:最好基於 單表來定義 sql 片段,提高片段的可重用性
在 sql 片段中不要包括 where
⑥foreach
需求:我們需要查詢 users 表中 id 分別為1,2,3的使用者
sql語句:select * from users where id=1 or id=2 or id=3 select * from users where id in (1,2,3)
建立一個 UserVo 類,裡面封裝一個 List<Integer> ids 的屬性
public class UserVo {
//封裝多個使用者的id
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
我們用 foreach 來改寫 select * from users where id=1 or id=2 or id=3
<select id="selectUsersByListId" parameterType="UserVo"
resultType="Users">
select * from users
<where>
<!-- collection:指定輸入物件中的集合屬性 item:每次遍歷生成的物件 open:開始遍歷時的拼接字串 close:結束時拼接的字串
separator:遍歷物件之間需要拼接的字串 select * from users where 1=1 and (id=1 or id=2 or
id=3) -->
<foreach collection="ids" item="id" open="and (" close=")"
separator="or">
id=#{id}
</foreach>
</where>
</select>
測試:
//根據id集合查詢users表資料
@Test
public void testSelectUsersByListId(){
UserVo uv = new UserVo();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
uv.setIds(ids);
List<Users> listUsers = mapper.selectUsersByListId(uv);
for(Users u : listUsers){
System.out.println(u);
}
session.close();
}
我們用 foreach 來改寫 select * from users where id in (1,2,3)
<select id="selectUsersByListId" parameterType="Users" resultType="Users">
select * from users
<where>
<!--
collection:指定輸入物件中的集合屬性
item:每次遍歷生成的物件
open:開始遍歷時的拼接字串
close:結束時拼接的字串
separator:遍歷物件之間需要拼接的字串
select * from user where 1=1 and id in (1,2,3)
-->
<foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
#{id}
</foreach>
</where>
</select>
單引數List的型別
<select id="dynamicForeachTest" resultType="Users">
select * from users where id in
<foreach collection="list" index="index" item="item" open="("
separator="," close=")">
#{item}
</foreach>
</select>
測試:
public List<User> dynamicForeachTest(List<Integer> ids);
@Test
public void testSelectUserByListId1(){
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
List<Users> listUsers = mapper.dynamicForeachTest(ids);
for(Users u : listUsers){
System.out.println(u);
}
}
單引數array陣列的型別
<select id="dynamicForeach2Test" resultType="User">
select * from users where id in
<foreach collection="array" index="index" item="item" open="("
separator="," close=")">
#{item}
</foreach>
</select>
public List<Users> dynamicForeach2Test(Integer[] ids);
@Test
public void dynamicForeach2Test(){
Integer[] ids={1,2,3};
List<Users> listUsers = mapper.dynamicForeach2Test(ids);
for(Users u : listUsers){
System.out.println(u);
}
}
將引數封裝成Map的型別
<select id="dynamicForeach3Test" resultType="User">
select * from users where name like "%"#{name}"%" and id in
<foreach collection="ids" index="index" item="item" open="("
separator="," close=")">
#{item}
</foreach>
</select>
public List<Users> dynamicForeach3Test(Map params);
測試:
@Test
public void dynamicForeach3Test() {
List ids = new ArrayList();
ids.add(28);
ids.add(29);
ids.add(30);
Map params = new HashMap();
params.put("ids", ids);
params.put("ame", "張");
List<Users> listUsers = mapper.dynamicForeach3Test(params);
for (Users u : listUsers) {
System.out.println(u);
}
}