使用Mybatis的Batch?Insert?Support?實(shí)現(xiàn)批量插入
Batch Insert Support 批量插入
在開(kāi)發(fā)中如果遇到需要批量insert的需求,可以使用Mybatis 的 Batch Insert Support 提高插入效率。
代碼實(shí)例(開(kāi)發(fā)的項(xiàng)目中截取的片段)
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
public int insertFolder(List<IpsCatalogFolderDetail> ips) {
?? ??? ?//獲取sql會(huì)話
?? ??? ?SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
? ? ? ? //通過(guò)新的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(); //沒(méi)有提交的數(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占用過(guò)高的問(wèn)題
經(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)文章
SpringBoot查詢PGSQL分表后的數(shù)據(jù)的代碼示例
數(shù)據(jù)庫(kù)用的pgsql,在表數(shù)據(jù)超過(guò)100w條的時(shí)候執(zhí)行定時(shí)任務(wù)進(jìn)行了分表,分表后表名命名為原的表名后面拼接時(shí)間,但是我在java業(yè)務(wù)代碼中,我想查詢之前的那條數(shù)據(jù)就查不到了,本文給大家介紹了SpringBoot中如何查詢PGSQL分表后的數(shù)據(jù),需要的朋友可以參考下2024-05-05
SpringMVC使用MultipartResolver實(shí)現(xiàn)文件上傳
MultipartResolver 用于處理文件上傳,當(dāng)收到請(qǐng)求時(shí) DispatcherServlet 的 checkMultipart() 方法會(huì)調(diào)用 MultipartResolver 的 isMultipart() 方法判斷請(qǐng)求中是否包含文件2023-02-02
Springboot 中使用 Aop代碼實(shí)戰(zhàn)教程
AOP的編程思想是把對(duì)類對(duì)象的橫切問(wèn)題點(diǎn),從業(yè)務(wù)邏輯中分離出來(lái),從而達(dá)到解耦的目的,增加代碼的復(fù)用性,提高開(kāi)發(fā)效率,這篇文章主要介紹了Springboot中使用Aop代碼實(shí)戰(zhàn)教程,需要的朋友可以參考下2023-07-07
Java中FilterInputStream和FilterOutputStream的用法詳解
這篇文章主要介紹了Java中FilterInputStream和FilterOutputStream的用法詳解,這兩個(gè)類分別用于封裝輸入和輸出流,需要的朋友可以參考下2016-06-06
Java游戲開(kāi)發(fā)之俄羅斯方塊的實(shí)現(xiàn)
俄羅斯方塊是一個(gè)最初由阿列克謝帕吉特諾夫在蘇聯(lián)設(shè)計(jì)和編程的益智類視頻游戲。本文和大家分享了利用Java語(yǔ)言實(shí)現(xiàn)這一經(jīng)典的小游戲的示例代碼,需要的可以參考一下2022-05-05
Windows10系統(tǒng)下修改jar中的文件并重新打包成jar文件然后運(yùn)行的操作步驟
這篇文章主要介紹了Windows10系統(tǒng)下修改jar中的文件并重新打包成jar文件然后運(yùn)行的操作步驟,文中通過(guò)圖文結(jié)合的形式給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-08-08

