您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“MyBatis如何實現批量插入數據”,內容詳細,步驟清晰,細節處理妥當,希望這篇“MyBatis如何實現批量插入數據”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
假設我們只插入一條數據的時候,SQL如下
insert into table ([列名],[列名]) values ([列值],[列值])); # 或者 insert into table values ([列值],[列值]))
當插入多條數據的時候,也就是需要批量插入的時候,SQL如下
insert into table ([列名],[列名]) VALUES ([列值],[列值])), ([列值],[列值])), ([列值],[列值]));
批量的用處:一次插入多條數據,這樣就可以降低與數據庫的IO次數,減少性能的損耗。
比如這里的抽象的SQL就是
insert into table (ID, PHONE,MESSAGE,APP_CODE,AREA_CODE,SEND_TYPE,SEND_TIME,CREATE_DATE,REMARK,serial_number) values (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,)
具體實現
<?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="com.scoreone.ap.mapper.MtTaskMapper"> <!--批量插入--> <insert id="insertList" parameterType="java.util.List"> insert into ap_mt_task (ID, PHONE, MESSAGE, APP_CODE, AREA_CODE, SEND_TYPE, SEND_TIME, CREATE_DATE, REMARK,serial_number ) VALUES <foreach collection="list" index="index" item="item" separator="," > (#{item.ID},#{item.PHONE},#{item.MESSAGE},#{item.APP_CODE},#{item.AREA_CODE}, #{item.SEND_TYPE},#{item.SEND_TIME},#{item.CREATE_DATE},#{item.REMARK},#{item.serial_number}) </foreach> </insert> </mapper>
也可以不用在value里用foreach
,在整個SQL語句外面用。
參數解釋
foreach的主要作用在構建in條件中,它可以在SQL語句中進行迭代一個集合。foreach元素的屬性主要有 collection,item,separator,index,open,close。
collection
:指定要遍歷的集合。表示傳入過來的參數的數據類型。該屬性是必須指定的,要做 foreach 的對象。在使用foreach的時候最關鍵的也是最容易出錯的就是collection屬性。在不同情況 下,該屬性的值是不一樣的,主要有一下3種情況:
a. 如果傳入的是單參數且參數類型是一個List的時候,collection屬性值為list
b. 如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值為array
c. 如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map。Map 對象沒有默認的鍵
item
:表示集合中每一個元素進行迭代時的別名。將當前遍歷出的元素賦值給指定的變量,然后用#{變量名},就能取出變量的值,也就是當前遍歷出的元素。
separator
:表示在每次進行迭代之間以什么符號作為分隔符。select * from tab where id in(1,2,3)相當于1,2,3之間的","
index
:索引。index指定一個名字,用于表示在迭代過程中,每次迭代到的位置。遍歷list的時候index就是索引,遍歷map的時候index表示的就是map的key,item就是map的值。
open
:表示該語句以什么開始,close表示以什么結束。
舉例
@Insert(“insert into blog(blogId,title,author) values(#blogId,#title,#author)”) public boolean saveBlog(Blog blog);
這種對于簡單的SQL可以使用法,對于復雜的SQL可讀性太差(會有以大堆拼接符號),不建議使用。
xml、注解兩種方式的區別:
foreach相當語句逐條INSERT語句執行,將出現如下問題:
(1)mapper接口的insert方法返回值將是最后一條INSERT語句的操作成功的記錄數目(就是0或1),而不是所有INSERT語句的操作成功的總記錄數目;
(2)當其中一條不成功時,不會進行整體回滾。
注解方式:當有一條插入不成功時,會整體回滾。
假設我們傳過來的List一次有 10000 條,但是我們數據庫批量插入不可能一下子插入 10000 條,我們就需要將這一批的數據進行限制,也就是再分成一小批一小批進行插入,比如下面,一次限制插入 15 條數據。
//舉例這里就是進行 task表 的批量插入,限制一次 15 條 public int insertList(ArrayList<MtTask> taskList) { //批量插入的時候,限制一批插入 15 條,效率會高一點,防止造成堆內存溢出異常 if (taskList.size() > 0) { int InsertSize = 15;//一次插入15條 //分成limit次發請求到數據庫 //這個算法就是防止不是在整除的時候少了一次,比如 32 個需要插四次 int limit = (taskList.size() + InsertSize - 1) / InsertSize;//需要插入多少次 //這個流的意思就是,進行 limit 次,每一次插入15個 //根據起始值seed(0),每次生成一個指定遞增值(n+1)的數,limit(limit)用于截斷流的長度,也就是進行limit次的里面的操作 Stream.iterate(0, n -> n + 1).limit(limit).forEach(a -> { // skip就是跳過前面(a * InsertSize)條數據,因為 a是從0開始,到limit,skip(0)的時候是空的不插入 // .limit(InsertSize)->限制每次插入數據的15條 .collect(Collectors.toList()->組成一個toList List<MtTask> mtTaskList = taskList.stream().skip(a * InsertSize).limit(InsertSize).collect(Collectors.toList()); //doSomething(); mtTaskMapper.insertList(mtTaskList); }); }
上面這是使用流的,下面是不用使用流的
/*不用流的方法*/ //集合的大小 int size = taskList.size(); //需要拆分成的每個集合大小 int newSize = 15; //需要需要拆分成的小集合數量(拆分沒有余數則取相除的結果,如果有余數則需要再加一個集合存放余數) //這個就是直接判斷出了之后有沒有余數,有就多加一次,沒有就整除剛好 int sum = size % newSize != 0 ? (size / newSize) + 1 : size / newSize; //循環參照大集合,能拆分成的集合有多少個就循環多少遍 for (int i = 0; i < sum; i++) { //如果當前下標+1 等于拆分成的集合數量,則說明這是最后一組(也可能僅能拆成一個集合 下標0 + 1 == 集合數量 1) if ((i + 1) == sum) { //截取的下標開始位 int startIndex = (i * newSize); //截取的結束下標位置 int endIndex = size; //插入 result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex)); } else { //截取的下標開始位 int startIndex = (i * newSize); //截取的結束下標位置 int endIndex = (i + 1) * newSize; result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex)); } }
=還有一種就是達到我們限制的數量就插入
@Override public int insertList(ArrayList<MtTask> taskList) { if(!CollectionUtils.isEmpty(taskList)){ List<MtTask> subList = new ArrayList<>(); int num = 0; for (MtTask mtTask : taskList ){ subList.add(mtTask); num ++ ; if(num >= 500){ mtTaskMapper.insertList(subList); subList.clear(); subList = new ArrayList<>(); } } if(num > 0){ mtTaskMapper.insertList(subList); subList.clear(); } } }
讀到這里,這篇“MyBatis如何實現批量插入數據”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。