MyBatis實(shí)現(xiàn)批量插入方法實(shí)例
一、SQL實(shí)現(xiàn)示例
假設(shè)我們只插入一條數(shù)據(jù)的時(shí)候,SQL如下
insert into table ([列名],[列名]) values ([列值],[列值])); # 或者 insert into table values ([列值],[列值]))
當(dāng)插入多條數(shù)據(jù)的時(shí)候,也就是需要批量插入的時(shí)候,SQL如下
insert into table ([列名],[列名]) VALUES ([列值],[列值])), ([列值],[列值])), ([列值],[列值]));
批量的用處:一次插入多條數(shù)據(jù),這樣就可以降低與數(shù)據(jù)庫(kù)的IO次數(shù),減少性能的損耗。
二、Mybatis通過(guò)Mapper.xml文件實(shí)現(xiàn)
比如這里的抽象的SQL就是
insert into table (ID, PHONE,MESSAGE,APP_CODE,AREA_CODE,SEND_TYPE,SEND_TIME,CREATE_DATE,REMARK,serial_number) values (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,)
具體實(shí)現(xiàn)
<?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
,在整個(gè)SQL語(yǔ)句外面用。
參數(shù)解釋
foreach的主要作用在構(gòu)建in條件中,它可以在SQL語(yǔ)句中進(jìn)行迭代一個(gè)集合。foreach元素的屬性主要有 collection,item,separator,index,open,close。
collection
:指定要遍歷的集合。表示傳入過(guò)來(lái)的參數(shù)的數(shù)據(jù)類(lèi)型。該屬性是必須指定的,要做 foreach 的對(duì)象。在使用foreach的時(shí)候最關(guān)鍵的也是最容易出錯(cuò)的就是collection屬性。在不同情況 下,該屬性的值是不一樣的,主要有一下3種情況:
- a. 如果傳入的是單參數(shù)且參數(shù)類(lèi)型是一個(gè)List的時(shí)候,collection屬性值為list
- b. 如果傳入的是單參數(shù)且參數(shù)類(lèi)型是一個(gè)array數(shù)組的時(shí)候,collection的屬性值為array
- c. 如果傳入的參數(shù)是多個(gè)的時(shí)候,我們就需要把它們封裝成一個(gè)Map了,當(dāng)然單參數(shù)也可以封裝成map。Map 對(duì)象沒(méi)有默認(rèn)的鍵
item
:表示集合中每一個(gè)元素進(jìn)行迭代時(shí)的別名。將當(dāng)前遍歷出的元素賦值給指定的變量,然后用#{變量名},就能取出變量的值,也就是當(dāng)前遍歷出的元素。
separator
:表示在每次進(jìn)行迭代之間以什么符號(hào)作為分隔符。select * from tab where id in(1,2,3)相當(dāng)于1,2,3之間的","
index
:索引。index指定一個(gè)名字,用于表示在迭代過(guò)程中,每次迭代到的位置。遍歷list的時(shí)候index就是索引,遍歷map的時(shí)候index表示的就是map的key,item就是map的值。
open
:表示該語(yǔ)句以什么開(kāi)始,close表示以什么結(jié)束。
三、在Mapper接口上使用注解
舉例
@Insert(“insert into blog(blogId,title,author) values(#blogId,#title,#author)”) public boolean saveBlog(Blog blog);
這種對(duì)于簡(jiǎn)單的SQL可以使用法,對(duì)于復(fù)雜的SQL可讀性太差(會(huì)有以大堆拼接符號(hào)),不建議使用。
xml、注解兩種方式的區(qū)別:
foreach相當(dāng)語(yǔ)句逐條INSERT語(yǔ)句執(zhí)行,將出現(xiàn)如下問(wèn)題:
(1)mapper接口的insert方法返回值將是最后一條INSERT語(yǔ)句的操作成功的記錄數(shù)目(就是0或1),而不是所有INSERT語(yǔ)句的操作成功的總記錄數(shù)目;
(2)當(dāng)其中一條不成功時(shí),不會(huì)進(jìn)行整體回滾。
注解方式:當(dāng)有一條插入不成功時(shí),會(huì)整體回滾。
四、限制一次批量插入數(shù)據(jù)的數(shù)量
假設(shè)我們傳過(guò)來(lái)的List一次有 10000 條,但是我們數(shù)據(jù)庫(kù)批量插入不可能一下子插入 10000 條,我們就需要將這一批的數(shù)據(jù)進(jìn)行限制,也就是再分成一小批一小批進(jìn)行插入,比如下面,一次限制插入 15 條數(shù)據(jù)。
//舉例這里就是進(jìn)行 task表 的批量插入,限制一次 15 條 public int insertList(ArrayList<MtTask> taskList) { //批量插入的時(shí)候,限制一批插入 15 條,效率會(huì)高一點(diǎn),防止造成堆內(nèi)存溢出異常 if (taskList.size() > 0) { int InsertSize = 15;//一次插入15條 //分成limit次發(fā)請(qǐng)求到數(shù)據(jù)庫(kù) //這個(gè)算法就是防止不是在整除的時(shí)候少了一次,比如 32 個(gè)需要插四次 int limit = (taskList.size() + InsertSize - 1) / InsertSize;//需要插入多少次 //這個(gè)流的意思就是,進(jìn)行 limit 次,每一次插入15個(gè) //根據(jù)起始值seed(0),每次生成一個(gè)指定遞增值(n+1)的數(shù),limit(limit)用于截?cái)嗔鞯拈L(zhǎng)度,也就是進(jìn)行l(wèi)imit次的里面的操作 Stream.iterate(0, n -> n + 1).limit(limit).forEach(a -> { // skip就是跳過(guò)前面(a * InsertSize)條數(shù)據(jù),因?yàn)?a是從0開(kāi)始,到limit,skip(0)的時(shí)候是空的不插入 // .limit(InsertSize)->限制每次插入數(shù)據(jù)的15條 .collect(Collectors.toList()->組成一個(gè)toList List<MtTask> mtTaskList = taskList.stream().skip(a * InsertSize).limit(InsertSize).collect(Collectors.toList()); //doSomething(); mtTaskMapper.insertList(mtTaskList); }); }
上面這是使用流的,下面是不用使用流的
/*不用流的方法*/ //集合的大小 int size = taskList.size(); //需要拆分成的每個(gè)集合大小 int newSize = 15; //需要需要拆分成的小集合數(shù)量(拆分沒(méi)有余數(shù)則取相除的結(jié)果,如果有余數(shù)則需要再加一個(gè)集合存放余數(shù)) //這個(gè)就是直接判斷出了之后有沒(méi)有余數(shù),有就多加一次,沒(méi)有就整除剛好 int sum = size % newSize != 0 ? (size / newSize) + 1 : size / newSize; //循環(huán)參照大集合,能拆分成的集合有多少個(gè)就循環(huán)多少遍 for (int i = 0; i < sum; i++) { //如果當(dāng)前下標(biāo)+1 等于拆分成的集合數(shù)量,則說(shuō)明這是最后一組(也可能僅能拆成一個(gè)集合 下標(biāo)0 + 1 == 集合數(shù)量 1) if ((i + 1) == sum) { //截取的下標(biāo)開(kāi)始位 int startIndex = (i * newSize); //截取的結(jié)束下標(biāo)位置 int endIndex = size; //插入 result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex)); } else { //截取的下標(biāo)開(kāi)始位 int startIndex = (i * newSize); //截取的結(jié)束下標(biāo)位置 int endIndex = (i + 1) * newSize; result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex)); } }
=還有一種就是達(dá)到我們限制的數(shù)量就插入
@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(); } } }
總結(jié)
到此這篇關(guān)于MyBatis實(shí)現(xiàn)批量插入的文章就介紹到這了,更多相關(guān)MyBatis批量插入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java基于API接口爬取商品數(shù)據(jù)的示例代碼
Java作為一種流行的編程語(yǔ)言,可以用于編寫(xiě)程序來(lái)調(diào)用這些API接口,從而獲取商品數(shù)據(jù),本文將介紹如何使用Java基于API接口爬取商品數(shù)據(jù),包括請(qǐng)求API、解析JSON數(shù)據(jù)、存儲(chǔ)數(shù)據(jù)等步驟,并提供相應(yīng)的代碼示例,感興趣的朋友跟隨小編一起看看吧2023-10-10Java實(shí)現(xiàn)單鏈表反轉(zhuǎn)的多種方法總結(jié)
這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)單鏈表反轉(zhuǎn)的多種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04詳解Spring Data JPA中Repository的接口查詢(xún)方法
repository代理有兩種方式從方法名中派生出特定存儲(chǔ)查詢(xún):通過(guò)直接從方法名派生查詢(xún)和通過(guò)使用一個(gè)手動(dòng)定義的查詢(xún)。本文將通過(guò)示例詳細(xì)講解Spring Data JPA中Repository的接口查詢(xún)方法,需要的可以參考一下2022-04-04關(guān)于Java并發(fā)編程中線程間協(xié)作的兩種方式
這篇文章主要介紹了關(guān)于Java并發(fā)編程中線程間協(xié)作的兩種方式,當(dāng)隊(duì)列滿(mǎn)時(shí),生產(chǎn)者需要等待隊(duì)列有空間才能繼續(xù)往里面放入商品,而在等待的期間內(nèi),生產(chǎn)者必須釋放對(duì)臨界資源的占用權(quán),這是消費(fèi)者模式,需要的朋友可以參考下2023-07-07SpringBoot中Bean生命周期自定義初始化和銷(xiāo)毀方法詳解
這篇文章給大家詳細(xì)介紹了SpringBoot中Bean生命周期自定義初始化和銷(xiāo)毀方法,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01基于Beanutils.copyProperties()的用法及重寫(xiě)提高效率
這篇文章主要介紹了Beanutils.copyProperties( )的用法及重寫(xiě)提高效率的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09