mybatis 傳入引數及其 foreach collection的三種用法
參考:
foreach標籤主要用於構建in條件,它可以在sql中對集合進行迭代,通常可以將之用到批量刪除、新增等操作中,示例如下:
<delete id="deleteBatch">
delete from user where id in
<foreach collection="array" item="id" index="index" open="(" close=")"separator=",">
#{id}
</foreach>
</delete>
我們假如說引數為---- int[] ids = {1,2,3,4,5} ----那麼列印之後的SQL為:delete form user where id in (1,2,3,4,5)
foreach元素的屬性主要有 item,index,collection,open,separator,close。
item表示集合中每一個元素進行迭代時的別名,
index指 定一個名字,用於表示在迭代過程中,每次迭代到的位置,
open表示該語句以什麼開始,
separator表示在每次進行迭代之間以什麼符號作為分隔 符,
close表示以什麼結束。
在使用foreach的時候最關鍵的也是最容易出錯的就是collection屬性,該屬性是必須指定的,但是在不同情況 下,該屬性的值是不一樣的,主要有一下3種情況:
1. 如果傳入的是單引數且引數型別是一個List的時候,collection屬性值為list
2. 如果傳入的是單引數且引數型別是一個array陣列的時候,collection的屬性值為array
3. 如果傳入的引數是多個的時候,我們就需要把它們封裝成一個Map了,當然單引數也可
1、傳入List
public List<Area> findUserListByIdList(List<Long> idList) {
return getSqlSession().selectList("com.liulanghan.findUserListByIdList", idList);
}
對應mapper:
<select id="findUserListByIdList" parameterType="java.util.ArrayList" resultType="User"> select * from user user <where> user.ID in ( <foreach collection="list" item="guard" index="index" separator=","> #{guard} </foreach> ) </where> </select>
即單獨傳入list時,foreach中的collection必須是list,不管變數的具體名稱是什麼。比如這裡變數名為idList, collection卻是list。
2、傳入陣列
public List<Area> findUserListByIdList(int[] ids) {
return getSqlSession().selectList("com.liulanghan.findUserListByIdList", ids);
}
對應mapper:
<select id="findUserListByIdList" parameterType="java.util.HashList" resultType="User">
select * from user user
<where>
user.ID in (
<foreach collection="array" item="guard" index="index"
separator=","> #{guard} </foreach>
)
</where>
</select>
單獨傳入陣列時,foreach中的collection必須是array,不管變數的具體名稱是什麼。比如這裡變數名為ids,collection卻是array
3、傳入map
public boolean exists(Map<String, Object> map){
Object count = getSqlSession().selectOne("com.liulanghan.exists", map);
int totalCount = Integer.parseInt(count.toString());
return totalCount > 0 ? true : false;
}
對應mapper:
<select id="exists" parameterType="java.util.HashMap" resultType="java.lang.Integer">
SELECT COUNT(*) FROM USER user
<where>
<if test="code != null">
and user.CODE = #{code}
</if>
<if test="id != null">
and user.ID = #{id}
</if>
<if test="idList !=null ">
and user.ID in (
<foreach collection="idList" item="guard" index="index"
separator=","> #{guard} </foreach>
)
</if>
</where>
</select>
MAP中有list或array時,foreach中的collection必須是具體list或array的變數名。比如這裡MAP含有一個名為idList的list,所以MAP中用idList取值,這點和單獨傳list或array時不太一樣。
4 、 傳入JAVA物件
public boolean findUserListByDTO(UserDTO userDTO){
Object count = getSqlSession().selectOne("com.liulanghan.exists", userDTO);
int totalCount = Integer.parseInt(count.toString());
return totalCount > 0 ? true : false;
}
對應mapper:
select id="findUserListByDTO" parameterType="UserDTO" resultType="java.lang.Integer">
SELECT COUNT(*) FROM USER user
<where>
<if test="code != null">
and user.CODE = #{code}
</if>
<if test="id != null">
and user.ID = #{id}
</if>
<if test="idList !=null ">
and user.ID in (
<foreach collection="idList" item="guard" index="index"
separator=","> #{guard} </foreach>
)
</if>
</where>
</select>
JAVA物件中有list或array時,foreach中的collection必須是具體list或array的變數名。比如這裡UserDTO含有一個名為idList的list,所以UserDTO中用idList取值,這點和單獨傳list或array時不太一樣。
6.取值
由上面可以看出,取值的時候用的是#{}。它具體的意思是告訴MyBatis建立一個預處理語句引數。
使用JDBC時,這樣的一個引數在SQL中會由一個“?”來標識,並被傳遞到一個新的預處理語句中,就像這樣:
// Similar JDBC code, NOT MyBatis…
String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
可以看到這個寫法比較簡單,MyBatis為我們做了很多預設的事情,具體的寫法應該如下:
#{property,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler,mode=OUT,resultMap=User}
上面sql語句對應欄位的含義:
property:屬性名,即程式碼傳入的變數名。
javaType:該欄位在JAVA中的型別,比如int。
jdbcType:該欄位在JDBC中的型別,比如NUMERIC。
typeHandler:型別處理器
mode:引數型別為IN,OUT或INOUT引數
resultMap:結果。
還好,MyBatis比較體諒我們,一般我們只需寫一個屬性名即可,如#{id},其他的如javaType和typeHandlerMybatis會自動幫我們填好。可是這樣有時也會出問題,比如出現CLOB欄位時。
由於JAVA程式碼中的String型別對應的預設typeHandler為StringTypeHandler,當用String型別處理時,如果String長度超過一定長度,就會報如下錯誤:
setString can only process strings of less than 32766 chararacters
解決辦法是指定該屬性的typeHandler,如下:
#{message,typeHandler=org.apache.ibatis.type.ClobTypeHandler}
我們也可以自定義typeHandler來處理需要的資料,具體這裡詳述。
JDBC型別是僅僅需要對插入,更新和刪除操作可能為空的列進行處理。這是JDBC的需要,而不是MyBatis的。一般不需要配置
mode、resultMap一般不需要,在寫儲存過程時會用到,這裡不詳述。
7.字串替換
一般情況下,我們採用#{}取值,產生預處理語句,但是有時我們可能不希望Mybatis來幫我們預處理,比如ORDER BY時,可以
採用如下寫法:
ORDER BY ${columnName}
這裡MyBatis不會修改或轉義字串。而是直接拼接到SQL字串後面。
重要:接受從使用者輸出的內容並提供給語句中不變的字串,這樣做是不安全的。這會導致潛在的SQL注入攻擊,因此你
不應該允許使用者輸入這些欄位,或者通常自行轉義並檢查。