1. 程式人生 > >mybatis 傳入引數及其 foreach collection的三種用法

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注入攻擊,因此你
 不應該允許使用者輸入這些欄位,或者通常自行轉義並檢查。