Mybatis中多個集合的迭代處理


如果有多個集合的迭代處理情況【使用MAP】

在SQL開發過程中,動態構建In集合條件查詢是比較常見的用法,在Mybatis中提供了foreach功能,該功能比較強大,它允許你指定一個集合,聲明集合項和索引變量,它們可以用在元素體內。它也允許你指定開放和關閉的字符串,在迭代之間放置分隔符。這個元素是很智能的,它不會偶然地附加多余的分隔符。下面是一個演示示例:

<select id="findByIdsMap" resultMap="BaseResultMap">
    Select
    <include refid="Base_Column_List" />
    from sys_user where user_id in
    <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

但由於官方文檔對這塊的使用,描述的比較簡短,細節上也被忽略掉了(可能是開源項目文檔一貫的問題吧),也使用不少同學在使用中遇到了問題。特別是foreach這個函數中,collection屬性做什么用,有什么注意事項。由於文檔不全,這塊只能通過源代碼剖析的方式來分析一下各個屬性的相關要求。

collection屬性的用途是接收輸入的數組或是List接口實現。但對於其名稱的要求,Mybatis在實現中還是有點不好理解的,所以需要特別注意這一點。

//關於這個源碼分析,大家可以不用看

下面開始分析源代碼(筆記使用的是Mybatis 3.0.5版本)

先找到Mybatis執行SQL配置解析的入口MapperMethod.java類中 public Object execute(Object[] args) 該方法是執行的入口.針對in集合查詢,對應用就是 selectForList或SelctForMap方法。

但不管調用哪個方法,都會對原來JDK傳入的參數 Object[]類型,通過 getParam方法轉換成一個Object,那這個方法是做什么的呢?分析源碼如下:

上圖中標紅的兩處,很驚訝的發現,一個參數與多個參數的處理方式是不同的(后續很多同學遇到的問題,就有一大部分出自這個地方)。

如果參數個數大於一個,則會被封裝成Map, key值如果使用了Mybatis的Param注解,則會使用該key值,否則默認統一使用數據序號,從1開始。這個問題先記下,繼續分析代碼,接下來如果是selectForList操作(其它操作就對應用相應方法),會調用DefaultSqlSession的public List selectList(String statement, Object parameter, RowBounds rowBounds) 方法

又一個發現,見源代碼如下:

上圖標紅部分,對參數又做了一次封裝,我們看一下代碼

現在有點清楚了,

如果參數類型是List,則必須在collecion中指定為list,

如果是數據組,則必須在collection屬性中指定為 array.

現在就問題就比較清楚了,如果是一個參數的話,collection的值取決於你的參數類型。

//注解方式我們沒有介紹,因為開發中使用的比較少

如果是多個值的話,除非使用注解Param指定,否則都是數字開頭,所以在collection中指定什么值都是無用的。下圖是debug顯示結果。

//----------------------------------------仔細看---------------------------------------------------------------------

針對上面分析的結果,下面給出了一個使用的解決方案,希望對大家對幫助。

在使用這個功能是需要特別注意以下規則:

1.當查詢的參數只有一個時

  findByIds(List<Long> ids)

A. 如果參數的類型是List, 則在使用時,collection屬性要必須指定為list

<select id="findByIdsMap" resultMap="BaseResultMap">
    Select
    <include refid="Base_Column_List" />
    from sys_user where user_id in
    <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
        #{item}
    </foreach>
 </select>



findByIds(Long[] ids)

B. 如果參數的類型是Array,則在使用時,collection屬性要必須指定為 array

<select id="findByIdsMap" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from sys_user where user_id in
    <foreach item="item" index="index" collection="array" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

2.當查詢的參數有多個時

例如findByIds(String name, Long[] ids)//這種方式不推薦使用,這種情況需要特別注意,在傳參數時,一定要改用Map方式, 這樣在collection屬性可以指定名稱,下面是一個示例

Map<StringObject> params = new HashMap<StringObject>(2);
params.put("name", name);
params.put("shxt", ids);
mapper.findByIdsMap(params);

next

<select id="findByIdsMap" resultMap="BaseResultMap">
         select
         <include refid="Base_Column_List" />
         from sys_user where user_id in
         <foreach item="item" index="index" collection="shxt" open="(" separator="," close=")">
             #{item}
         </foreach>
      </select>

完整的示例如下:

例如有一個查詢功能,Mapper接口文件定義如下方法:

List<Jria> findByIds(Long... ids);

使用 in 查詢的sql拼裝方法如下:

 <select id="findbyIds" resultMap="BaseResultMap">
     select
     <include refid="Base_Column_List" />
     from sys_user where user_id in
     <foreach item="item" index="index" collection="array" open="(" separator="," close=")">
         #{item}
     </foreach>
  </select>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM