ibatis批量插入-iterate標籤應用

      項目開發中在很多地方可能會遇到同時插入多條記錄到數據庫的業務場景,如果業務級別循環單條插入數據會不斷建立連接且有多個事務,這個時候如果業務的事務執行頻率相當較高的話(高併發),對數據庫的性能影響是比較大的;爲了提高效率,批量操作會是不錯的選擇,一次批量操作只需要建立一次連接且一個事務,能很大程度上提高數據庫的效率。

      批量插入操作的sql語句原型如下:

  1. insert  into    
  2.     wsjiang_test(col1, col2, col3)   
  3. values    
  4.     (col1_v, col2_v, col3_v),   
  5.     (col1_v, col2_v, col3_v),  
  6.      ... 

      這裏我們以ibatis爲例,進行應用說明!

 

     一、 ibatis iterate標籤配置說明

  1. < iterate   
  2.     property =""  /*可選,   
  3.         從傳入的參數集合中使用屬性名去獲取值,   
  4.         這個必須是一個List類型,   
  5.         否則會出現OutofRangeException,   
  6.         通常是參數使用java.util.Map時才使用,   
  7.         如果傳入的參數本身是一個java.util.List, 不能只用這個屬性.  
  8.         不知道爲啥官網: http://ibatis.apache.org/docs/dotnet/datamapper/ch03s09.html#id386679  
  9.         說這個屬性是必須的, 但是測試的時候是可以不設置這個屬性的, 還望那位大蝦知道, 講解一下.  
  10.         */  
  11.     conjunction =""  /*可選,   
  12.         iterate可以看作是一個循環,   
  13.         這個屬性指定每一次循環結束後添加的符號,   
  14.          比如使每次循環是OR的, 則設置這個屬性爲OR*/  
  15.     open =""  /*可選, 循環的開始符號*/  
  16.     close =""  /*可選, 循環的結束符號*/  
  17.     prepend =""  /*可選, 加在open指定的符號之前的符號*/  
  18. > </ iterate >

 

       二、 ibatis iterate標籤使用示例

              1、批量查詢

  1. < select  id ="iterate_query"  parameterClass ="java.util.List" >   
  2.     <![CDATA[  
  3.         selelct * from wsjiang_test where id=1 
  4.     ]]>   
  5.     < iterate  prepend ="prepend"  conjunction ="conn"  open ="open"  colse ="close" >   
  6.         /*使用java.util.List作爲參數不能設置property屬性*/  
  7.         <![CDATA[  
  8.             #v[]#  
  9.         ]]> /*這裏的"[]"是必須的, 要不然ibatis會把v直接解析爲一個String*/  
  10.     </ iterate >   
  11. </ select >

             如果傳入一個List爲[123,234,345], 上面的配置將得到一個sql語句:

                   select * from wsjiang_test where id=1 prepend open 123 conn 234 conn 345 close

 

            2、批量插入

               A、不使用open/close屬性

  1. < insert  id =" iterate_insert1 "  parameterClass ="java.util.List" >   
  2.     <![CDATA[  
  3.         insert into wsjinag_test( col1 , col2 , col3 ) values  
  4.     ]]>    
  5.     < iterate  conjunction ="," >   
  6.         <![CDATA[  
  7.             (#test[]. col1 #, # test []. col2 #, # test []. col3 #)  
  8.         ]]>   
  9.     </ iterate >   
  10. </ insert > 

              上面的配置將得到一個sql語句:

                   insert  into wsjiang_test( col1, col2, col3 ) values  (?, ?, ?) , (?, ?, ?) , (?, ?, ?) 

 

              B、使用open/close屬性

  1. < insert  id ="betchAddNewActiveCode"  parameterClass ="java.util.List" >    
  2.    <![CDATA[  
  3.         insert into wsjinag_test( col1 , col2 , col3 ) values  
  4.     ]]> 
  5.     < iterate  conjunction =","  open ="("  close =")" >   
  6.         <![CDATA[  
  7.             /*這裏不加"("和")"*/  
  8.             #test[]. col1 #, # test []. col2 #, # test []. col3 #
  9.         ]]>   
  10.     </ iterate >   
  11. </ insert > 

             上面的配置將得到一個sql語句:

                  insert  into wsjiang_test( col1, col2, col3 ) values  (?, ?, ?    ,     ?, ?, ?     ,     ?, ?, ?)

 

         這兩種使用方式區別是相當大的. conjunction, open 和close這幾個屬性需小心使用,將其區分開.

 

    三、單條插入返回新增記錄主鍵

          通常情況,ibatis的insert方法需要返回新增記錄的主鍵,但並非任何表的insert操作都會返回主鍵(這是一個陷阱);要返回這個新增記錄的主鍵,前提是表的主鍵是自增型的,或者是Sequence的;且必須啓用ibatis的selectKey 標籤; 否則獲取新增記錄主鍵的值爲0或者null。

         ibatis的配置:

  1. < insert  id =" iterate_insert1 "  parameterClass ="Object" >   
  2.     <![CDATA[  
  3.         insert into wsjinag_test( col1 , col2 , col3 ) 
  4.         values   (# col1 #, # col2 #, # col3 #)  
  5.     ]]>    
  6.     < selectKey   keyProperty ="id" resultClass= "Long" >   
  7.         <![CDATA[  
  8.             SELECT LAST_INSERT_ID() AS value  
  9.         ]]>   
  10.     </ selectKey >   
  11. </ insert >

 

  四、 插入返回 新增記錄數

      在第三節中已經講清楚通過ibatis的insert方法只能得到新增記錄的ID; 如果對於無需知道新增記錄ID,只需要知道有沒有插入成功的業務場景時,特別是對於批量插入,配置的selectKey 可能會有問題時,一次插入多條,拿不到新增的ID,這時我們就只能返回插入成功的記錄數來區分是否新增成功!但是insert方法是不會返回記錄數;於是我們可以使用ibatis的update方法來調用沒有配置 selectKey 標籤的insert語句,這樣就能返回影響(插入)的記錄數了!





mybatis批量插入和刪除


實體類:

複製代碼
import java.io.Serializable;
public class AttachmentTable implements Serializable {
    private static final long serialVersionUID = 8325882509007088323L;
    private Integer id;
    // 附件名稱
    private String name;
    // 日誌ID
    private Integer logid;
    // 附件URL
    private String url;

    // getter/setter.......
}
複製代碼

Mapper接口:

複製代碼
import java.util.List;
import model.AttachmentTable;
public interface AttachmentTableMapper {
  int insert(AttachmentTable record);
  void insertByBatch(List<AttachmentTable> attachmentTables);
}
複製代碼

Mapper.xml:

複製代碼
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.AttachmentTableMapper">
    <resultMap id="BaseResultMap" type="model.AttachmentTable">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="logID" jdbcType="INTEGER" property="logid" />
    </resultMap>
    <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="model.AttachmentTable">
        <result column="url" jdbcType="LONGVARCHAR" property="url" />
    </resultMap>
    <sql id="Base_Column_List">
        id, name, logID
    </sql>
    <sql id="Blob_Column_List">
        url
    </sql>
    <insert id="insert" parameterType="model.AttachmentTable">
        insert into attachment_table (id, name, logID,url)
        values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{logid,jdbcType=INTEGER},#{url,jdbcType=LONGVARCHAR})
    </insert>
    <insert id="insertByBatch" parameterType="java.util.List">
        insert into attachment_table (name, logID,url)
        values
        <foreach collection="list" item="item" index="index" separator=",">
            (#{item.name,jdbcType=VARCHAR}, #{item.logid,jdbcType=INTEGER},#{item.url,jdbcType=LONGVARCHAR})
        </foreach>
    </insert>
</mapper>
複製代碼

【注:標紅的地方是需要注意的地方,我第一次做時直接“#{name,jdbcType=VARCHAR}”,沒有加前綴“item”,導致報錯“找不到name”】

 (二)多參數批量刪除示例

package com.vrv.linkdood.app.workreport.demomodule.mapper;import org.apache.ibatis.annotations.Param;public interface AttachmentTableMapper {
    void deleteByLogIdAndNames(@Param("logid") Integer logID, @Param("names") String[] names);
}
複製代碼
    <delete id="deleteByLogIdAndNames">
        delete from attachment_table
        where logid = #{logid,jdbcType=INTEGER} AND NAME IN
        <foreach collection="names" item="item" index="index" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>
複製代碼

 

複製代碼

屬性 描述
item 循環體中的具體對象。支持屬性的點路徑訪問,如item.age,item.info.details。
具體說明:在list和數組中是其中的對象,在map中是value。
該參數爲必選。
collection

要做foreach的對象,作爲入參時,List<?>對象默認用list代替作爲鍵,數組對象有array代替作爲鍵,Map對象沒有默認的鍵。
當然在作爲入參時可以使用@Param("keyName")來設置鍵,設置keyName後,list,array將會失效。 除了入參這種情況外,還有一種作爲參數對象的某個字段的時候。舉個例子:
如果User有屬性List ids。入參是User對象,那麼這個collection = "ids"
如果User有屬性Ids ids;其中Ids是個對象,Ids有個屬性List id;入參是User對象,那麼collection = "ids.id"
上面只是舉例,具體collection等於什麼,就看你想對那個元素做循環。
該參數爲必選。

separator 元素之間的分隔符,例如在in()的時候,separator=","會自動在元素中間用“,“隔開,避免手動輸入逗號導致sql錯誤,如in(1,2,)這樣。該參數可選。
open foreach代碼的開始符號,一般是(和close=")"合用。常用在in(),values()時。該參數可選。
close foreach代碼的關閉符號,一般是)和open="("合用。常用在in(),values()時。該參數可選。
index 在list和數組中,index是元素的序號,在map中,index是元素的key,該參數可選。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章