ibatis批量插入-iterate標籤應用
專案開發中在很多地方可能會遇到同時插入多條記錄到資料庫的業務場景,如果業務級別迴圈單條插入資料會不斷建立連線且有多個事務,這個時候如果業務的事務執行頻率相當較高的話(高併發),對資料庫的效能影響是比較大的;為了提高效率,批量操作會是不錯的選擇,一次批量操作只需要建立一次連線且一個事務,能很大程度上提高資料庫的效率。
批量插入操作的sql語句原型如下:
- insert into
- wsjiang_test(col1, col2, col3)
- values
- (col1_v, col2_v, col3_v),
- (col1_v, col2_v, col3_v),
- ...
這裡我們以ibatis為例,進行應用說明!
一、 ibatis iterate標籤配置說明
- < iterate
- property ="" /*可選,
- 從傳入的引數集合中使用屬性名去獲取值,
- 這個必須是一個List型別,
- 否則會出現OutofRangeException,
- 通常是引數使用java.util.Map時才使用,
- 如果傳入的引數本身是一個java.util.List, 不能只用這個屬性.
- 不知道為啥官網: http://ibatis.apache.org/docs/dotnet/datamapper/ch03s09.html#id386679
- 說這個屬性是必須的, 但是測試的時候是可以不設定這個屬性的, 還望那位大蝦知道, 講解一下.
- */
- conjunction ="" /*可選,
- iterate可以看作是一個迴圈,
- 這個屬性指定每一次迴圈結束後新增的符號,
- 比如使每次迴圈是OR的, 則設定這個屬性為OR*/
- open ="" /*可選, 迴圈的開始符號*/
- close ="" /*可選, 迴圈的結束符號*/
- prepend ="" /*可選, 加在open指定的符號之前的符號*/
-
>
二、 ibatis iterate標籤使用示例
1、批量查詢
- < select id ="iterate_query" parameterClass ="java.util.List" >
- <![CDATA[
-
selelct * from wsjiang_test where id=1
- ]]>
- < iterate prepend ="prepend" conjunction ="conn" open ="open" colse ="close" >
- /*使用java.util.List作為引數不能設定property屬性*/
- <![CDATA[
- #v[]#
- ]]> /*這裡的"[]"是必須的, 要不然ibatis會把v直接解析為一個String*/
- </ iterate >
- </ 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屬性
- < insert id =" iterate_insert1 " parameterClass ="java.util.List" >
- <![CDATA[
- insert into wsjinag_test( col1 , col2 , col3 ) values
- ]]>
- < iterate conjunction ="," >
- <![CDATA[
- (#test[]. col1 #, # test []. col2 #, # test []. col3 #)
- ]]>
- </ iterate >
-
</ insert >
上面的配置將得到一個sql語句:
insert into wsjiang_test( col1, col2, col3 ) values (?, ?, ?) , (?, ?, ?) , (?, ?, ?)
B、使用open/close屬性
- < insert id ="betchAddNewActiveCode" parameterClass ="java.util.List" >
- <![CDATA[
- insert into wsjinag_test( col1 , col2 , col3 ) values
- ]]>
- < iterate conjunction ="," open ="(" close =")" >
- <![CDATA[
- /*這裡不加"("和")"*/
- #test[]. col1 #, # test []. col2 #, # test []. col3 #
- ]]>
- </ iterate >
-
</ insert >
上面的配置將得到一個sql語句:
insert into wsjiang_test( col1, col2, col3 ) values (?, ?, ? , ?, ?, ? , ?, ?, ?)
這兩種使用方式區別是相當大的. conjunction, open 和close這幾個屬性需小心使用,將其區分開.
三、單條插入返回新增記錄主鍵
通常情況,ibatis的insert方法需要返回新增記錄的主鍵,但並非任何表的insert操作都會返回主鍵(這是一個陷阱);要返回這個新增記錄的主鍵,前提是表的主鍵是自增型的,或者是Sequence的;且必須啟用ibatis的selectKey 標籤; 否則獲取新增記錄主鍵的值為0或者null。
ibatis的配置:
- < insert id =" iterate_insert1 " parameterClass ="Object" >
- <![CDATA[
-
insert into wsjinag_test( col1 , col2 , col3 )
- values (# col1 #, # col2 #, # col3 #)
- ]]>
- < selectKey keyProperty ="id" resultClass= "Long" >
- <![CDATA[
- SELECT LAST_INSERT_ID() AS value
- ]]>
- </ selectKey >
- </ 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物件沒有預設的鍵。 |
separator | 元素之間的分隔符,例如在in()的時候,separator=","會自動在元素中間用“,“隔開,避免手動輸入逗號導致sql錯誤,如in(1,2,)這樣。該引數可選。 |
open | foreach程式碼的開始符號,一般是(和close=")"合用。常用在in(),values()時。該引數可選。 |
close | foreach程式碼的關閉符號,一般是)和open="("合用。常用在in(),values()時。該引數可選。 |
index | 在list和陣列中,index是元素的序號,在map中,index是元素的key,該引數可選。 |