使用Mybatis的Batch?Insert?Support?實(shí)現(xiàn)批量插入
Batch Insert Support 批量插入
在開發(fā)中如果遇到需要批量insert的需求,可以使用Mybatis 的 Batch Insert Support 提高插入效率。
代碼實(shí)例(開發(fā)的項(xiàng)目中截取的片段)
@Autowired private SqlSessionTemplate sqlSessionTemplate; public int insertFolder(List<IpsCatalogFolderDetail> ips) { ?? ??? ?//獲取sql會(huì)話 ?? ??? ?SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false); ? ? ? ? //通過新的session獲取mapper,而不是常規(guī)的spring管理注入 ? ? ? ? IipsCatalogFolderDetailDao folderDetailDao = session.getMapper(IipsCatalogFolderDetailDao.class); ? ? ? ? int size = ips.size(); ? ? ? ? //如果有父類子類兩層都需要批量插入也可 ? ? ? ? try { ? ? ? ? //外層循環(huán) ? ? ? ? ? ? for (int i = 0; i < size; i++) { ? ? ? ? ? ? ? ? ? ? ips.get(i).setType("folder"); ? ? ? ? ? ? ? ? ? ? //用上面在session中獲取的mapper進(jìn)行插入操作 ? ? ? ? ? ? ? ? ? ? folderDetailDao.insertFolder(ips.get(i)); ? ? ? ? ? ? ? ? //內(nèi)層循環(huán) ? ? ? ? ? ? ? ? String cs = ips.get(i).getContentIds(); ? ? ? ? ? ? ? ? if (StringUtils.isNotBlank(cs)){ ? ? ? ? ? ? ? ? ? ? ? ? List<String> con = JSON.parseArray(cs,String.class); ? ? ? ? ? ? ? ? ? ? if (cs != null && con.size() > 0) { ? ? ? ? ? ? ? ? ? ? ? ? for (int j = 0; j < con.size(); j++) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IpsCatalogFolderDetail ifd = new IpsCatalogFolderDetail(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifd.setParentCode(ips.get(i).getCode()); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifd.setContentId(con.get(j)); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifd.setType("contents"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//同樣用上面在session中獲取的mapper進(jìn)行插入操作 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? folderDetailDao.insertFolder(ifd); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? //最后批量提交 ? ? ? ? ? ? ? ? ? ? if (i % 200 == 0 || i == size - 1) { ? ? ? ? ? ? ? ? ? ? ? ? session.commit();//200個(gè)提交一次,手動(dòng)提交,提交后無(wú)法回滾 ? ? ? ? ? ? ? ? ? ? ? ? session.clearCache(); //清理緩存,防止溢出 ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? }catch (Exception e) { ? ? ? ? ? ? System.out.println(e.toString()); ? ? ? ? ? ?session.rollback(); //沒有提交的數(shù)據(jù)可以回滾 ? ? ? ? } finally { ? ? ? ? ? ? session.close(); ? ? ? ? } ? ? ? ? return 0; ? ? }
另外有時(shí)我們?cè)诓迦氲臅r(shí)候需要先查詢數(shù)據(jù)是否已存在,如果也需要批量操作可將insert和update語(yǔ)句合并,然后就可以繼續(xù)使用Batch Insert了
ORACLE數(shù)據(jù)庫(kù)sql示例
@Insert("merge into ips_catalog_folder_detail fd " + ? ? ? ? ? ? "using(select #{code,jdbcType=VARCHAR} c from dual)t " + ? ? ? ? ? ? "on(fd.FOLDERID = t.c)" + ? ? ? ? ? ?? ? ? ? ? ? ? "when matched then"+ ?? ??? ??? ?"update set "+ ?? ??? ??? ?...(省略)... ?? ??? ??? ?"where ..."+ ? ? ? ? ? ? "when not matched then insert(" + ? ? ? ? ? ? "fd.PROD_LINE," + ? ? ? ? ? ? "fd.TYPE," + ? ? ? ? ? ? "fd.PARENTFOLDERCODE," + ? ? ? ? ? ? "fd.FOLDERID," + ? ? ? ? ? ? "fd.FOLDERCODE," + ? ? ? ? ? ? "fd.FOLDERNAME," + ? ? ? ? ? ? "fd.COLUMN_SORTINDEX," + ? ? ? ? ? ? "fd.DESCRIPTION," + ? ? ? ? ? ? "fd.CONTENTID," + ? ? ? ? ? ? "fd.CREATETIME" + ? ? ? ? ? ? ")" + ? ? ? ? ? ? "VALUES" + ? ? ? ? ? ? "(" + ? ? ? ? ? ? "#{prod_line}," + ? ? ? ? ? ? "#{type,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{parentCode,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{code,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{aliasCode,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{name,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{sortIndex,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{desc,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{contentId,jdbcType=VARCHAR}," + ? ? ? ? ? ? "#{createTime,jdbcType=VARCHAR}" + ? ? ? ? ? ? ")") ? ? ? ? ? ? int insertFolder(IpsCatalogFolderDetail fd);
MYSQL示例:
REPLACE INTO users (id,name,age) VALUES(1, '張雨綺', 32);?
批量插入幾千條數(shù)據(jù)優(yōu)化(foreach)
項(xiàng)目中有一個(gè)耗時(shí)較長(zhǎng)的Job存在CPU占用過高的問題
經(jīng)排查發(fā)現(xiàn),主要時(shí)間消耗在往MyBatis中批量插入數(shù)據(jù)。mapper configuration是用foreach循環(huán)做的,差不多是這樣。
<insert id="batchInsert" parameterType="java.util.List"> ? ? insert into USER (id, name) values ? ? <foreach collection="list" item="model" index="index" separator=",">? ? ? ? ? (#{model.id}, #{model.name}) ? ? </foreach> </insert>
優(yōu)化代碼
可以看 http://www.mybatis.org/mybatis-dynamic-sql/docs/insert.html 中 Batch Insert Support 標(biāo)題里的內(nèi)容)
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH); try { ? ? SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class); ? ? List<SimpleTableRecord> records = getRecordsToInsert(); // not shown ? ? ? BatchInsert<SimpleTableRecord> batchInsert = insert(records) ? ? ? ? ? ? .into(simpleTable) ? ? ? ? ? ? .map(id).toProperty("id") ? ? ? ? ? ? .map(firstName).toProperty("firstName") ? ? ? ? ? ? .map(lastName).toProperty("lastName") ? ? ? ? ? ? .map(birthDate).toProperty("birthDate") ? ? ? ? ? ? .map(employed).toProperty("employed") ? ? ? ? ? ? .map(occupation).toProperty("occupation") ? ? ? ? ? ? .build() ? ? ? ? ? ? .render(RenderingStrategy.MYBATIS3); ? ? ? batchInsert.insertStatements().stream().forEach(mapper::insert); ? ? session.commit(); } finally { ? ? session.close(); }
總結(jié)一下,如果MyBatis需要進(jìn)行批量插入,推薦使用 ExecutorType.BATCH 的插入方式,如果非要使用 <foreach>的插入的話,需要將每次插入的記錄控制在 20~50 左右
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java List Object[]轉(zhuǎn)換成List T的實(shí)例
這篇文章主要介紹了Java List Object[]轉(zhuǎn)換成List T的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-09-09用JAVA實(shí)現(xiàn)單鏈表,檢測(cè)字符串是否是回文串
這篇文章主要介紹了使用JAVA實(shí)現(xiàn)單鏈表,檢測(cè)字符串是否是回文串,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11關(guān)于SpringCloud中Ribbon的7種負(fù)載均衡策略解析
這篇文章主要介紹了關(guān)于SpringCloud中Ribbon的7種負(fù)載均衡策略解析,服務(wù)端負(fù)載均衡器的問題是,它提供了更強(qiáng)的流量控制權(quán),但無(wú)法滿足不同的消費(fèi)者希望使用不同負(fù)載均衡策略的需求,而使用不同負(fù)載均衡策略的場(chǎng)景確實(shí)是存在的,需要的朋友可以參考下2023-07-07Oracle + Mybatis實(shí)現(xiàn)批量插入、更新和刪除示例代碼
利用MyBatis動(dòng)態(tài)SQL的特性,我們可以做一些批量的操作,下面這篇文章主要給大家介紹了關(guān)于Oracle + Mybatis實(shí)現(xiàn)批量插入、更新和刪除的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2018-01-01SpringBoot加載不出來(lái)application.yml文件的解決方法
這篇文章主要介紹了SpringBoot加載不出來(lái)application.yml文件的解決方法,文中通過示例代碼講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作有一定的幫助,需要的朋友跟著小編來(lái)一起來(lái)學(xué)習(xí)吧2023-12-12Java 中的 DataInputStream 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
DataInputStream 是數(shù)據(jù)輸入流。它繼承于FilterInputStream。接下來(lái)通過本文給大家介紹Java 中的 DataInputStream的相關(guān)知識(shí),需要的朋友參考下吧2017-05-05Java平臺(tái)調(diào)試體系原理分析和實(shí)踐整理 遠(yuǎn)程Debug
這篇文章主要介紹了Java平臺(tái)調(diào)試體系原理分析和實(shí)踐整理 遠(yuǎn)程Debug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03MyBatis-Plus枚舉和自定義主鍵ID的實(shí)現(xiàn)步驟
這篇文章主要給大家介紹了關(guān)于MyBatis-Plus枚舉和自定義主鍵ID的相關(guān)資料,文中通過實(shí)例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02