通過實(shí)例講解了用mybatis對一張表進(jìn)行的CRUD操作,但是我們發(fā)現(xiàn)寫的 SQL 語句都比較簡單,如果有比較復(fù)雜的業(yè)務(wù),我們需要寫復(fù)雜的 SQL 語句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引號,空格等缺失可能都會導(dǎo)致錯(cuò)誤。 那么怎么去解決這個(gè)問題呢?這就是本篇所講的使用 mybatis 動態(tài)SQL,通過 if, choose, when, otherwise, trim, where, set, foreach等標(biāo)簽, 1. if 語句 (簡單的條件判斷) 2. choose (when,otherwize) ,相當(dāng)于java 語言中的 switch ,與 jstl 中的choose 很類似. 3. trim (對包含的內(nèi)容加上 prefix,或者 suffix 等,前綴,后綴) 4. where (主要是用來簡化sql語句中where條件判斷的,能智能的處理 and or ,不必?fù)?dān)心多余導(dǎo)致語法錯(cuò)誤) 5. set (主要用于更新時(shí)) 6. foreach (在實(shí)現(xiàn) mybatis in 語句查詢時(shí)特別有用) 可組合成非常靈活的SQL語句,從而在提高 SQL 語句的準(zhǔn)確性的同時(shí),也大大提高了開發(fā)人員的效率。 我們以 User 表為例來說明:  1、動態(tài)SQL:if 語句 根據(jù) username 和 sex 來查詢數(shù)據(jù)。如果username為空,那么將只根據(jù)sex來查詢;反之只根據(jù)username來查詢 首先不使用 動態(tài)SQL 來書寫 1 2 3 4 5 6 | <select id= "selectUserByUsernameAndSex"
resultType= "user" parameterType= "com.ys.po.User" >
<!-- 這里和普通的sql 查詢語句差不多,對于只有一個(gè)參數(shù),后面的 #{id}表示占位符,里面不一定要寫id,
寫啥都可以,但是不要空著,如果有多個(gè)參數(shù)則必須寫pojo類里面的屬性 -->
select * from user where username=#{username} and sex=#{sex}
</select>
|
上面的查詢語句,我們可以發(fā)現(xiàn),如果 #{username} 為空,那么查詢結(jié)果也是空,如何解決這個(gè)問題呢?使用 if 來判斷 1 2 3 4 5 6 7 8 9 10 | <select id= "selectUserByUsernameAndSex" resultType= "user" parameterType= "com.ys.po.User" >
select * from user where
< if test= "username != null" >
username=#{username}
</ if >
< if test= "username != null" >
and sex=#{sex}
</ if >
</select>
|
這樣寫我們可以看到,如果 sex 等于 null,那么查詢語句為 select * from user where username=#{username},但是如果usename 為空呢?那么查詢語句為 select * from user where and sex=#{sex},這是錯(cuò)誤的 SQL 語句,如何解決呢?請看下面的 where 語句 2、動態(tài)SQL:if+where 語句1 2 3 4 5 6 7 8 9 10 11 12 | <select id= "selectUserByUsernameAndSex" resultType= "user" parameterType= "com.ys.po.User" >
select * from user
<where>
< if test= "username != null" >
username=#{username}
</ if >
< if test= "username != null" >
and sex=#{sex}
</ if >
</where>
</select>
|
這個(gè)“where”標(biāo)簽會知道如果它包含的標(biāo)簽中有返回值的話,它就插入一個(gè)'where’。此外,如果標(biāo)簽返回的內(nèi)容是以AND 或OR 開頭的,則它會剔除掉。 3、動態(tài)SQL:if+set 語句 同理,上面的對于查詢 SQL 語句包含 where 關(guān)鍵字,如果在進(jìn)行更新操作的時(shí)候,含有 set 關(guān)鍵詞,我們怎么處理呢? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!-- 根據(jù) id 更新 user 表的數(shù)據(jù) -->
<update id= "updateUserById" parameterType= "com.ys.po.User" >
update user u
<set>
< if test= "username != null and username != ''" >
u.username = #{username},
</ if >
< if test= "sex != null and sex != ''" >
u.sex = #{sex}
</ if >
</set>
where id=#{id}
</update>
|
這樣寫,如果第一個(gè)條件 username 為空,那么 sql 語句為:update user u set u.sex=? where id=? 如果第一個(gè)條件不為空,那么 sql 語句為:update user u set u.username = ? ,u.sex = ? where id=? 4、動態(tài)SQL:choose(when,otherwise) 語句 有時(shí)候,我們不想用到所有的查詢條件,只想選擇其中的一個(gè),查詢條件有一個(gè)滿足即可,使用 choose 標(biāo)簽可以解決此類問題,類似于 Java 的 switch 語句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <select id= "selectUserByChoose" resultType= "com.ys.po.User" parameterType= "com.ys.po.User" >
select * from user
<where>
<choose>
<when test= "id !='' and id != null" >
id=#{id}
</when>
<when test= "username !='' and username != null" >
and username=#{username}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
|
也就是說,這里我們有三個(gè)條件,id,username,sex,只能選擇一個(gè)作為查詢條件 如果 id 不為空,那么查詢語句為:select * from user where id=? 如果 id 為空,那么看username 是否為空,如果不為空,那么語句為 select * from user where username=?; 如果 username 為空,那么查詢語句為 select * from user where sex=? 5、動態(tài)SQL:trim 語句 trim標(biāo)記是一個(gè)格式化的標(biāo)記,可以完成set或者是where標(biāo)記的功能 ①、用 trim 改寫上面第二點(diǎn)的 if+where 語句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <select id= "selectUserByUsernameAndSex" resultType= "user" parameterType= "com.ys.po.User" >
select * from user
<!-- <where>
< if test= "username != null" >
username=#{username}
</ if >
< if test= "username != null" >
and sex=#{sex}
</ if >
</where> -->
<trim prefix= "where" prefixOverrides= "and | or" >
< if test= "username != null" >
and username=#{username}
</ if >
< if test= "sex != null" >
and sex=#{sex}
</ if >
</trim>
</select>
|
prefix:前綴 prefixoverride:去掉第一個(gè)and或者是or ?、?、用 trim 改寫上面第三點(diǎn)的 if+set 語句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!-- 根據(jù) id 更新 user 表的數(shù)據(jù) -->
<update id= "updateUserById" parameterType= "com.ys.po.User" >
update user u
<!-- <set>
< if test= "username != null and username != ''" >
u.username = #{username},
</ if >
< if test= "sex != null and sex != ''" >
u.sex = #{sex}
</ if >
</set> -->
<trim prefix= "set" suffixOverrides= "," >
< if test= "username != null and username != ''" >
u.username = #{username},
</ if >
< if test= "sex != null and sex != ''" >
u.sex = #{sex},
</ if >
</trim>
where id=#{id}
</update>
|
suffix:后綴 suffixoverride:去掉最后一個(gè)逗號(也可以是其他的標(biāo)記,就像是上面前綴中的and一樣) 6、動態(tài)SQL: SQL 片段 有時(shí)候可能某個(gè) sql 語句我們用的特別多,為了增加代碼的重用性,簡化代碼,我們需要將這些代碼抽取出來,然后使用時(shí)直接調(diào)用。 比如:假如我們需要經(jīng)常根據(jù)用戶名和性別來進(jìn)行聯(lián)合查詢,那么我們就把這個(gè)代碼抽取出來,如下: 1 2 3 4 5 6 7 8 9 | <!-- 定義 sql 片段 -->
<sql id= "selectUserByUserNameAndSexSQL" >
< if test= "username != null and username != ''" >
AND username = #{username}
</ if >
< if test= "sex != null and sex != ''" >
AND sex = #{sex}
</ if >
</sql>
|
引用 sql 片段 1 2 3 4 5 6 7 8 | <select id= "selectUserByUsernameAndSex" resultType= "user" parameterType= "com.ys.po.User" >
select * from user
<trim prefix= "where" prefixOverrides= "and | or" >
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid= "selectUserByUserNameAndSexSQL" ></include>
<!-- 在這里還可以引用其他的 sql 片段 -->
</trim>
</select>
|
注意:①、最好基于 單表來定義 sql 片段,提高片段的可重用性 ?、?、在 sql 片段中不要包括 where 7、動態(tài)SQL: foreach 語句 需求:我們需要查詢 user 表中 id 分別為1,2,3的用戶 sql語句:select * from user where id=1 or id=2 or id=3 select * from user where id in (1,2,3) ①、建立一個(gè) UserVo 類,里面封裝一個(gè) List<Integer> ids 的屬性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.ys.vo;
import java.util.List;
public class UserVo {
//封裝多個(gè)用戶的id
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this .ids = ids;
}
}
|
②、我們用 foreach 來改寫 select * from user where id=1 or id=2 or id=3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <select id= "selectUserByListId" parameterType= "com.ys.vo.UserVo" resultType= "com.ys.po.User" >
select * from user
<where>
<!--
collection:指定輸入對象中的集合屬性
item:每次遍歷生成的對象
open:開始遍歷時(shí)的拼接字符串
close:結(jié)束時(shí)拼接的字符串
separator:遍歷對象之間需要拼接的字符串
select * from user 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>
|
測試: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //根據(jù)id集合查詢user表數(shù)據(jù)
@Test
public void testSelectUserByListId(){
String statement = "com.ys.po.userMapper.selectUserByListId" ;
UserVo uv = new UserVo();
List<Integer> ids = new ArrayList<>();
ids.add( 1 );
ids.add( 2 );
ids.add( 3 );
uv.setIds(ids);
List<User> listUser = session.selectList(statement, uv);
for (User u : listUser){
System.out.println(u);
}
session.close();
}
|
③、我們用 foreach 來改寫 select * from user where id in (1,2,3) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <select id= "selectUserByListId" parameterType= "com.ys.vo.UserVo" resultType= "com.ys.po.User" >
select * from user
<where>
<!--
collection:指定輸入對象中的集合屬性
item:每次遍歷生成的對象
open:開始遍歷時(shí)的拼接字符串
close:結(jié)束時(shí)拼接的字符串
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>
|
8、總結(jié) 其實(shí)動態(tài) sql 語句的編寫往往就是一個(gè)拼接的問題,為了保證拼接準(zhǔn)確,我們最好首先要寫原生的 sql 語句出來,然后在通過 mybatis 動態(tài)sql 對照著改,防止出錯(cuò)。
|