這是mybatis系列第5篇伊诵。沒看前文的建議先去【Java冢狐】公眾號中查看前文,方便理解和掌握。
說到底Mybatis常見的傳參形式無非是傳遞一個參數(shù)逸寓、Map、Java對象覆山,亦或是多個參數(shù)竹伸。下面就分別對這些進行講解和說明。
傳遞一個參數(shù)
傳遞一個參數(shù)相對來說較為簡單
用法
Mapper接口方法中只有一個參數(shù)簇宽,如:
UserModel getByName(String name);
Mapper xml引用這個name參數(shù):
#{任意合法名稱}
如:#{name}勋篓、#{val}、${x}等等寫法都可以引用上面name參數(shù)的值晦毙。直接使用即可相當(dāng)?shù)姆奖愫秃唵?/p>
傳遞一個Map參數(shù)
用法
如果我們需要傳遞的參數(shù)比較多生巡,參數(shù)個數(shù)是動態(tài)的,那么我們可以將這些參數(shù)放在一個map中见妒,key為參數(shù)名稱孤荣,value為參數(shù)的值。在工作中须揣,這種可以說是最常見的盐股。大多數(shù)情況下都可以進行使用
Mapper接口中可以這么定義,如:
List<UserModel> getByMap(Map<String,Object> map);
如我們傳遞:
Map<String, Object> map = new HashMap<>();
map.put("id", 1L);
map.put("name", "冢狐");
對應(yīng)的mapper xml中可以通過#{map中的key}可以獲取key在map中對應(yīng)的value的值作為參數(shù)耻卡,如:
SELECT * FROM t_user WHERE id=#{id} OR name = #{name}
傳遞一個java對象參數(shù)
當(dāng)參數(shù)比較多疯汁,但是具體有多少個參數(shù)我們是確定的時候,我們可以將這些參數(shù)放在一個javabean對象中卵酪。這樣也有利于理解幌蚊,知道需要傳遞那些參數(shù),不想map一樣對于傳遞的參數(shù)不是很明確溃卡。
如我們想通過userId和userName查詢溢豆,可以定義一個dto對象,屬性添加對應(yīng)的get瘸羡、set方法漩仙,如:
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserFindDto {
private Long userId;
private String userName;
}
傳遞java對象的方式相對于map的方式更清晰一些,可以明確知道具體有哪些參數(shù),而傳遞map队他,我們是不知道這個map中具體需要哪些參數(shù)的卷仑,map對參數(shù)也沒有約束,參數(shù)可以隨意傳麸折,建議多個參數(shù)的情況下選擇通過java對象進行傳參锡凝。
傳遞多個參數(shù)
上面我們介紹的都是傳遞一個參數(shù),那么是否可以傳遞多個參數(shù)呢磕谅?我們來試試吧私爷。
多參數(shù)mybatis的處理
mybatis處理多個參數(shù)的時候,會將多個參數(shù)封裝到一個map中膊夹,map的key為參數(shù)的名稱衬浑,java可以通過反射獲取方法參數(shù)的名稱,下面這個方法:
UserModel getByIdOrName(Long id, String name);
編譯之后放刨,方法參數(shù)的名稱通過反射獲取的并不是id工秩、name,而是arg0进统、arg1助币,也就是說編譯之后,方法真實的參數(shù)名稱會丟失螟碎,會變成arg+參數(shù)下標的格式眉菱。
所以上面?zhèn)鬟f的參數(shù)相當(dāng)于傳遞了下面這樣的一個map:
Map<String,Object> map = new HashMap<>();
map.put("arg0",id);
map.put("arg1",name);
所以說我們的方法真實的參數(shù)名稱會丟失,如果要想使用真實的參數(shù)名稱掉分,就需要在編譯java代碼使用javac命令的時候帶上-parameters參數(shù)俭缓,當(dāng)編譯代碼的時候加上這個參數(shù),方法的實際名稱會被編譯到class字節(jié)碼文件中酥郭,當(dāng)通過反射獲取方法名稱的時候就不是arg0华坦、arg1這種格式了,而是真實的參數(shù)名稱:id不从、name了惜姐。
我們來修改一下maven的配置讓maven編譯代碼的時候加上這個參數(shù),修改pom.xml中的build元素椿息,這個元素中加入下面代碼:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
idea中編譯代碼也加一下這個參數(shù)歹袁,操作如下:
點擊File->Settings->Build,Execution,Deployment->Java Compiler,如下圖:
下面我們將xml中的getByIdOrName對應(yīng)的sql修改成下面這樣:
SELECT * FROM t_user WHERE id=#{arg0} OR name = #{arg1} LIMIT 1
使用maven命令重新編譯一下chat01的代碼寝优,cmd命令中mybatis-demo/pom.xml所在目錄執(zhí)行下面命令:
mvn clean compile -pl :chat01
參數(shù)名稱變成了真實的名稱了宇攻,但是還是有param1、param2倡勇,方法參數(shù)名稱不管怎么變,編譯方式如何變化,param1, param2始終在這里妻熊,這個param1, param2就是為了應(yīng)對不同的編譯方式導(dǎo)致參數(shù)名稱而發(fā)生變化的夸浅,mybatis內(nèi)部除了將參數(shù)按照名稱->值的方式放入map外,還會按照參數(shù)的順序放入一些值扔役,這些值的key就是param+參數(shù)位置帆喇,這個位置從1開始的,所以id是第一個參數(shù)亿胸,對應(yīng)的key是param1坯钦,name對應(yīng)的key是param2,value對應(yīng)的還是參數(shù)的值侈玄,所以mybatis對于參數(shù)的處理相當(dāng)于下面過程:
Map<String,Object> map = new HashMap<>();
map.put("反射獲取的參數(shù)id的名稱",id);
map.put("反射獲取的參數(shù)name的名稱",name);
map.put("param1",id);
map.put("param2",name);
使用注意
- 使用參數(shù)名稱的方式對編譯環(huán)境有很強的依賴性婉刀,如果編譯中加上了
-parameters
參數(shù),參數(shù)實際名稱可以直接使用序仙,如果沒有加突颊,參數(shù)名稱就變成arg下標
的格式了,這種很容易出錯 - sql中使用
param1潘悼、param2律秃、paramN
這種方式來引用多參數(shù),對參數(shù)的順序依賴性特別強治唤,如果有人把參數(shù)的順序調(diào)整了或者調(diào)整了參數(shù)的個數(shù)棒动,后果就是災(zāi)難性的,所以這種方式不建議大家使用宾添。
多參數(shù)中用@param指定參數(shù)名稱
剛才上面講了多參數(shù)傳遞的使用上面船惨,對參數(shù)名稱和順序有很強的依賴性,容易導(dǎo)致一些嚴重的錯誤辞槐。
mybatis也為我們考慮到了這種情況掷漱,可以讓我們自己去指定參數(shù)的名稱,通過@param(“參數(shù)名稱”)來給參數(shù)指定名稱榄檬。
/**
* 通過id或者name查詢
*
* @param id
* @param name
* @return
*/
UserModel getByIdOrName(@Param("userId") Long id, @Param("userName") String name);
上面我們通過@Param注解給兩個參數(shù)明確指定了名稱卜范,分別是userId、userName鹿榜,對應(yīng)的user.xml中也做一下調(diào)整海雪,如下:
<!-- 通過id或者name查詢 -->
<select id="getByIdOrName" resultType="zhonghu.mybatis.chat01.UserModel">
<![CDATA[
SELECT * FROM user WHERE id=#{userId} OR name = #{userName} LIMIT 1
]]>
</select>
ResultHandler作為參數(shù)
用法
查詢的數(shù)量比較大的時候,返回一個List集合占用的內(nèi)存還是比較多的舱殿,比如我們想導(dǎo)出很多數(shù)據(jù)奥裸,實際上如果我們通過jdbc的方式,遍歷ResultSet的next方法沪袭,一條條處理湾宙,而不用將其存到List集合中再取處理。
mybatis中也支持我們這么做,可以使用ResultHandler對象侠鳄,猶如其名埠啃,這個接口是用來處理結(jié)果的,先看一下其定義:
public interface ResultHandler<T> {
void handleResult(ResultContext<? extends T> resultContext);
}
里面有1個方法伟恶,方法的參數(shù)是ResultContext類型的碴开,這個也是一個接口,看一下源碼:
public interface ResultContext<T> {
T getResultObject();
int getResultCount();
boolean isStopped();
void stop();
}
4個方法:
- getResultObject:獲取當(dāng)前行的結(jié)果
- getResultCount:獲取當(dāng)前結(jié)果到第幾行了
- isStopped:判斷是否需要停止遍歷結(jié)果集
- stop:停止遍歷結(jié)果集
ResultContext接口有一個實現(xiàn)類org.apache.ibatis.executor.result.DefaultResultContext博秫,mybatis中默認會使用這個類潦牛。
最后
- 如果覺得看完有收獲,希望能關(guān)注一下挡育,順便給我點個贊巴碗,這將會是我更新的最大動力,感謝各位的支持
- 歡迎各位關(guān)注我的公眾號【java冢狐】静盅,專注于java和計算機基礎(chǔ)知識良价,保證讓你看完有所收獲,不信你打我
- 求一鍵三連:點贊蒿叠、轉(zhuǎn)發(fā)明垢、在看。
- 如果看完有不同的意見或者建議市咽,歡迎多多評論一起交流痊银。感謝各位的支持以及厚愛。
——我是冢狐施绎,和你一樣熱愛編程溯革。
歡迎關(guān)注公眾號“ Java冢狐”,獲取最新消息