MyBatis中動(dòng)態(tài)sql的實(shí)現(xiàn)方法示例
1. 動(dòng)態(tài)sql
動(dòng)態(tài)sql是mybatis中的一個(gè)核心,什么是動(dòng)態(tài)sql?
動(dòng)態(tài)sql即對(duì)sql語(yǔ)句進(jìn)行靈活操作,通過(guò)表達(dá)式進(jìn)行判斷,對(duì)sql進(jìn)行靈活拼接、組裝。
MyBatis的強(qiáng)大特性之一便是它的動(dòng)態(tài) SQL。如果你有使用 JDBC 或其他類似框架的經(jīng)驗(yàn),你就能體會(huì)到根據(jù)不同條件拼接 SQL 語(yǔ)句有多么痛苦。拼接的時(shí)候要確保不能忘了必要的空格,還要注意省掉列名列表最后的逗號(hào)。有些時(shí)候,SQL語(yǔ)句where條件中,需要一些安全判斷,例如按某一條件查詢時(shí)如果傳入的參數(shù)是空,此時(shí)查詢出的結(jié)果很可能是空的,也許我們需要參數(shù)為空時(shí),是查出全部的信息。使用Oracle的序列、mySQL的函數(shù)生成Id。這時(shí)我們可以使用動(dòng)態(tài)SQL。利用動(dòng)態(tài) SQL 這一特性可以徹底擺脫這種痛苦。通常使用動(dòng)態(tài) SQL 不可能是獨(dú)立的一部分,MyBatis 當(dāng)然使用一種強(qiáng)大的動(dòng)態(tài) SQL 語(yǔ)言來(lái)改進(jìn)這種情形,這種語(yǔ)言可以被用在任意的 SQL 映射語(yǔ)句中。動(dòng)態(tài) SQL 元素和使用 JSTL 或其他類似基于 XML 的文本處理器相似。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來(lái)消除其他元素。
MyBatis中用于實(shí)現(xiàn)動(dòng)態(tài)SQL的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
就拿上一篇博文中對(duì)用戶的綜合查詢一例來(lái)說(shuō):
select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%'
假如這個(gè)user是null咋整?或者user.sex或者user.username為null呢?所以更嚴(yán)謹(jǐn)?shù)淖龇☉?yīng)該是在執(zhí)行這個(gè)語(yǔ)句之前要先進(jìn)行判斷才對(duì),確保都不為空,那么我再去查詢。這就涉及到了mybatis中的動(dòng)態(tài)sql了。
在mybatis中,動(dòng)態(tài)sql可以使用標(biāo)簽來(lái)表示,這很類似于jstl表達(dá)式,我們可以將上面的sql語(yǔ)句改成動(dòng)態(tài)sql,如下:
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User"> select * from user <!-- where可以自動(dòng)去掉條件中的第一個(gè)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>
上面的代碼很好理解,主要就是加了一些判斷,條件不為空,才進(jìn)行查詢條件的拼接,讓mybatis動(dòng)態(tài)的去執(zhí)行。那么在測(cè)試代碼中,我們可以故意的將user.sex不賦初值,就可以看到查詢的結(jié)果是不一樣的。
2. sql片段
那么現(xiàn)在還有個(gè)問(wèn)題,如果好幾個(gè)statement都需要這樣做,而且動(dòng)態(tài)sql部分都一樣,這就會(huì)導(dǎo)致一些代碼的重復(fù),所以如果遇到這種情況,我們就應(yīng)該抽取,動(dòng)態(tài)sql也可以抽取,我們可以將動(dòng)態(tài)的這部分sql抽取成sql片段,然后在具體的statement中引用進(jìn)來(lái)即可。如下:
<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片段起個(gè)名字而已,內(nèi)部就是上面的where動(dòng)態(tài)部分,然后我們將上面原來(lái)的動(dòng)態(tài)部分改成對(duì)這個(gè)sql片段的引用,如下:
<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
還有個(gè)問(wèn)題:如果我們要向sql傳遞數(shù)組或List該咋整呢?mybatis使用的是foreach解析。為了模擬這個(gè)場(chǎng)景,我們將上面的查詢改成多個(gè)id查詢,有兩種查詢方式:
SELECT * FROM USER WHERE id=1 OR id=12 OR id=17SELECT * FROM USER WHERE id IN(1,12,17)
首先有一點(diǎn)很明確,既然要使用多個(gè)id進(jìn)行查詢,那么多個(gè)id肯定要作為參數(shù)傳進(jìn)來(lái),所以存儲(chǔ)多個(gè)id的List需要放到UserQueryVo中作為一個(gè)屬性,這點(diǎn)很好理解,所以我們先在UserQueryVo中增加這個(gè)屬性:
//傳入多個(gè)id private List<Integer> ids;
然后我們修改UserMapper.xml中的sql片段(還是寫在sql片段中),如下:
<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>
下面簡(jiǎn)單介紹一下這個(gè)foreach中相關(guān)屬性的作用:
collection:指定輸入對(duì)象中的集合屬性,這里就是這個(gè)ids。 item:表示每個(gè)遍歷生成的對(duì)象,自己起個(gè)名兒,在foreach體中使用。 open:開(kāi)始遍歷時(shí)拼接的sql串。 close:結(jié)束遍歷時(shí)拼接的sql串。 separator:遍歷的兩個(gè)對(duì)象中需要拼接的sql串。
我們測(cè)試一下,然后看下控制臺(tái)打印出來(lái)的sql就很容易理解了。測(cè)試程序:
@Testpublic void testFindUserList() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建UserMapper對(duì)象,mybatis自動(dòng)生成mapper代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //創(chuàng)建包裝對(duì)象,設(shè)置查詢條件 UserQueryVo userQueryVo = new UserQueryVo(); User user = new User(); //由于這里使用動(dòng)態(tài)sql,如果不設(shè)置某個(gè)值,條件不會(huì)拼接在sql中 user.setSex("男"); user.setUsername("倪升武"); //傳入多個(gè)id List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(12); ids.add(17); userQueryVo.setIds(ids); userQueryVo.setUser(user); //調(diào)用userMapper的方法 List<User> list = userMapper.findUserList(userQueryVo); System.out.println(list);}
看下控制臺(tái)打印出的sql:
select * from user WHERE user.sex = ? and user.username like '%倪升武%' AND ( id=? OR id=? OR id=? )
注意一個(gè)細(xì)節(jié):在mybatis中,如果輸入的是Integer或者int類型的0,上面那個(gè)if判斷標(biāo)簽返回的是false,也就是說(shuō),即使非空非'',也不會(huì)拼接標(biāo)簽體中的sql。
所以mybatis自動(dòng)的將多個(gè)id拼接到了sql中。那么另外一個(gè)sql的實(shí)現(xiàn)就不再贅述了,跟上面的一樣,唯一不同的就是sql片段部分,如下:
<!-- 使用右邊的sql拼接:AND id IN(1,12,17) --> <foreach collection="ids" item="user_id" open="AND id IN(" close=")" separator=","> #{user_id}</foreach>
總結(jié):
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Java實(shí)現(xiàn)定時(shí)任務(wù)最簡(jiǎn)單的3種方法
幾乎在所有的項(xiàng)目中,定時(shí)任務(wù)的使用都是不可或缺的,如果使用不當(dāng)甚至?xí)斐少Y損,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)定時(shí)任務(wù)最簡(jiǎn)單的3種方法,本文通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06java根據(jù)開(kāi)始時(shí)間結(jié)束時(shí)間計(jì)算中間間隔日期的實(shí)例代碼
這篇文章主要介紹了java根據(jù)開(kāi)始時(shí)間結(jié)束時(shí)間計(jì)算中間間隔日期的實(shí)例代碼,需要的朋友可以參考下2019-05-05聊聊DecimalFormat的用法及各符號(hào)的意義
這篇文章主要介紹了DecimalFormat的用法及各符號(hào)的意義,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot 簽到獎(jiǎng)勵(lì)實(shí)現(xiàn)方案的示例代碼
這篇文章主要介紹了SpringBoot 簽到獎(jiǎng)勵(lì)實(shí)現(xiàn)方案的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08使用Java實(shí)現(xiàn)對(duì)兩個(gè)秒級(jí)時(shí)間戳相加
在現(xiàn)代應(yīng)用程序開(kāi)發(fā)中,時(shí)間戳的處理是一個(gè)常見(jiàn)需求,特別是當(dāng)我們需要對(duì)時(shí)間戳進(jìn)行運(yùn)算時(shí),比如時(shí)間戳的相加操作,本文我們將探討如何使用Java對(duì)兩個(gè)秒級(jí)時(shí)間戳進(jìn)行相加,并展示詳細(xì)的代碼示例和運(yùn)行結(jié)果,需要的朋友可以參考下2024-08-08解決@ConfigurationProperties注解的使用及亂碼問(wèn)題
這篇文章主要介紹了解決@ConfigurationProperties注解的使用及亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Java命令行運(yùn)行錯(cuò)誤之找不到或無(wú)法加載主類問(wèn)題的解決方法
這篇文章主要給大家介紹了關(guān)于Java命令行運(yùn)行錯(cuò)誤之找不到或無(wú)法加載主類問(wèn)題的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01Java Spring 控制反轉(zhuǎn)(IOC)容器詳解
這篇文章主要為大家詳細(xì)介紹了Spring控制反轉(zhuǎn)IoC入門使用的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10詳解mybatis.generator配上最新的mysql 8.0.11的一些坑
這篇文章主要介紹了詳解mybatis.generator配上最新的mysql 8.0.11的一些坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10