1. 動態sql
動態sql是mybatis中的一個核心,什么是動態sql?
動態sql即對sql語句進行靈活操作,通過表達式進行判斷,對sql進行靈活拼接、組裝。
mybatis的強大特性之一便是它的動態 sql。如果你有使用 jdbc 或其他類似框架的經驗,你就能體會到根據不同條件拼接 sql 語句有多么痛苦。拼接的時候要確保不能忘了必要的空格,還要注意省掉列名列表最后的逗號。有些時候,sql語句where條件中,需要一些安全判斷,例如按某一條件查詢時如果傳入的參數是空,此時查詢出的結果很可能是空的,也許我們需要參數為空時,是查出全部的信息。使用oracle的序列、mysql的函數生成id。這時我們可以使用動態sql。利用動態 sql 這一特性可以徹底擺脫這種痛苦。通常使用動態 sql 不可能是獨立的一部分,mybatis 當然使用一種強大的動態 sql 語言來改進這種情形,這種語言可以被用在任意的 sql 映射語句中。動態 sql 元素和使用 jstl 或其他類似基于 xml 的文本處理器相似。mybatis 采用功能強大的基于 ognl 的表達式來消除其他元素。
mybatis中用于實現動態sql的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
就拿上一篇博文中對用戶的綜合查詢一例來說:
1
|
select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%' |
假如這個user是null咋整?或者user.sex或者user.username為null呢?所以更嚴謹的做法應該是在執行這個語句之前要先進行判斷才對,確保都不為空,那么我再去查詢。這就涉及到了mybatis中的動態sql了。
在mybatis中,動態sql可以使用標簽來表示,這很類似于jstl表達式,我們可以將上面的sql語句改成動態sql,如下:
1
2
3
4
5
6
7
8
9
10
11
|
<select id= "finduserlist" parametertype= "mybatis.po.userqueryvo" resulttype= "mybatis.po.user" > select * from user <!-- where可以自動去掉條件中的第一個and --> <where> < if test= "user!=null" > < if test= "user.sex!=null and user.sex!=''" > and user.sex = #{user.sex} </ if > < if test= "user.username!=null and user.username!=''" > and user.username like '%${user.username}%' </ if > </ if > </where> </select> |
上面的代碼很好理解,主要就是加了一些判斷,條件不為空,才進行查詢條件的拼接,讓mybatis動態的去執行。那么在測試代碼中,我們可以故意的將user.sex不賦初值,就可以看到查詢的結果是不一樣的。
2. sql片段
那么現在還有個問題,如果好幾個statement都需要這樣做,而且動態sql部分都一樣,這就會導致一些代碼的重復,所以如果遇到這種情況,我們就應該抽取,動態sql也可以抽取,我們可以將動態的這部分sql抽取成sql片段,然后在具體的statement中引用進來即可。如下:
1
2
3
4
5
6
7
8
|
<sql id= "query_user_where" > < if test= "user!=null" > < if test= "user.sex!=null and user.sex!=''" > and user.sex = #{user.sex} </ if > < if test= "user.username!=null and user.username!=''" > and user.username like '%${user.username}%' </ if > </ if > </sql> |
id是給該sql片段起個名字而已,內部就是上面的where動態部分,然后我們將上面原來的動態部分改成對這個sql片段的引用,如下:
1
2
3
4
5
6
7
|
<select id= "finduserlist" parametertype= "mybatis.po.userqueryvo" resulttype= "mybatis.po.user" > select * from user <where> <!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要在前面加上namespace --> <include refid= "query_user_where" ></include> <!-- 還可以引用其他sql片段 --> </where> </select> |
3. foreach
還有個問題:如果我們要向sql傳遞數組或list該咋整呢?mybatis使用的是foreach解析。為了模擬這個場景,我們將上面的查詢改成多個id查詢,有兩種查詢方式:
1
|
select * from user where id= 1 or id= 12 or id=17select * from user where id in( 1 , 12 , 17 ) |
首先有一點很明確,既然要使用多個id進行查詢,那么多個id肯定要作為參數傳進來,所以存儲多個id的list需要放到userqueryvo中作為一個屬性,這點很好理解,所以我們先在userqueryvo中增加這個屬性:
1
2
|
//傳入多個id private list<integer> ids; |
然后我們修改usermapper.xml中的sql片段(還是寫在sql片段中),如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<sql id= "query_user_where" > < if test= "user!=null" > < if test= "user.sex!=null and user.sex!=''" > and user.sex = #{user.sex} </ if > < if test= "user.username!=null and user.username!=''" > and user.username like '%${user.username}%' </ if > </ if > < if test= "ids!=null" > <!-- 使用右邊的sql拼接:and (id= 1 or id= 12 or id= 17 ) --> <foreach collection= "ids" item= "user_id" open= "and (" close= ")" separator= "or" > id=#{user_id} </foreach> </ if > </sql> |
下面簡單介紹一下這個foreach中相關屬性的作用:
collection:指定輸入對象中的集合屬性,這里就是這個ids。 item:表示每個遍歷生成的對象,自己起個名兒,在foreach體中使用。 open:開始遍歷時拼接的sql串。 close:結束遍歷時拼接的sql串。 separator:遍歷的兩個對象中需要拼接的sql串。
我們測試一下,然后看下控制臺打印出來的sql就很容易理解了。測試程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@testpublic void testfinduserlist() throws exception { sqlsession sqlsession = sqlsessionfactory.opensession(); //創建usermapper對象,mybatis自動生成mapper代理對象 usermapper usermapper = sqlsession.getmapper(usermapper. class ); //創建包裝對象,設置查詢條件 userqueryvo userqueryvo = new userqueryvo(); user user = new user(); //由于這里使用動態sql,如果不設置某個值,條件不會拼接在sql中 user.setsex( "男" ); user.setusername( "倪升武" ); //傳入多個id list<integer> ids = new arraylist<integer>(); ids.add( 1 ); ids.add( 12 ); ids.add( 17 ); userqueryvo.setids(ids); userqueryvo.setuser(user); //調用usermapper的方法 list<user> list = usermapper.finduserlist(userqueryvo); system.out.println(list);} |
看下控制臺打印出的sql:
1
|
select * from user where user.sex = ? and user.username like '%倪升武%' and ( id=? or id=? or id=? ) |
注意一個細節:在mybatis中,如果輸入的是integer或者int類型的0,上面那個if判斷標簽返回的是false,也就是說,即使非空非'',也不會拼接標簽體中的sql。
所以mybatis自動的將多個id拼接到了sql中。那么另外一個sql的實現就不再贅述了,跟上面的一樣,唯一不同的就是sql片段部分,如下:
1
2
3
|
<!-- 使用右邊的sql拼接:and id in( 1 , 12 , 17 ) --> <foreach collection= "ids" item= "user_id" open= "and id in(" close= ")" separator= "," > #{user_id}</foreach> |
總結:
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://yq.aliyun.com/articles/667279