觉得不错的,麻烦点个免费的赞

觉得不错的,麻烦点个免费的赞

觉得不错的,麻烦点个免费的赞

需求

  在一个和平的某天,客户提了一个需求,想导入10个年份的历史数据,
  10个年份的历史数据,提供了一个Excel文件大小为10M,
  里面数据16千条,关联的主子表有10个,所以本次一次性需要导入10多万条数据;

总结

开发中常见的mybatis插入有3种类型:①普通插入、②foreach遍历参数式、③ExecutorType.BATCH插入
一般导入数据不会用第一种,一般是导入插入10条以下的短数据,例如简单列少的基础数据插入; 
实际开发选择用foreach,还是.BATCH,一般要看本次导入数据有多少条,及导入的表有多少列,
【条数*表列数】<2千】选择用foreach;超过2千数据选择.BATCH 或者 分批次foreach处理;

个人10万数据实践中,.BATCH速度最快,通用,建议使用;
5千到1万时,可以使用分批次foreach处理;

①普通插入 
INSERT INTO XX_PROJECT (ID,NAME,CODE) VALUES    (  #{ID},#{NAME},#{CODE}  )
②foreach遍历参数式 
INSERT INTO XX_PROJECT  (ID,NAME,CODE) VALUES    
<foreach  collection="list" item="item" index="index" separator="," >
	 (  #{item.ID},#{item.NAME},#{item.CODE}  )
</foreach>ExecutorType.BATCH插入后续介绍具体使用方法

处理逻辑

①原本的思路是,先使用foreach一次性插入1+数据到数据库,发生内存溢出了

②后面,我对从Excel读取过来的数据进行分割,每次拆500条数据,
再使用mybatis的foreach标签去批量插入,执行成功了,速度也还行,
但是数据再多点的时候,速度也不是很快,该慢的还是慢,
我也尝试过调大分批次的总量为800条,但是速度也不是很明显;
后续看资料发现,foreach采用的占位符替换数据的思路,在占位符过多的时候,
解析的时间会边长,插入数据过1万的时候,不建议采用;

③最后是尝试了,mybatis的ExecutorType.BATCH,速度明显变快,
10几万条数据成功插入到数据库,只要了20多秒;

最终解决代码

// XXProjectDao.java dao层方法
void insertProject(Map<String,Object> map);

// XXProjectDao.java对应的XXProjectDaoMapper语句
<insert id="insertProject" parameterType="java.util.Map">
    INSERT INTO XX_PROJECT (ID,NAME,CODE) VALUES
    ( #{ID},#{NAME},#{CODE} )
</insert>

// service业务层具体实现
SqlSession sqlSession=null;
try{
     long c1 = System.currentTimeMillis();
     sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
     XXProjectDao mapper = sqlSession.getMapper(XXProjectDao.class);
     int batchSize = 5000;//每次到5000提交一次
     for (int i = 0; i < projectList.size(); i++) {
         mapper.insertProject(projectList.get(i));
         if((i!=0 && i%batchSize==0) || i==projectList.size()-1){
             sqlSession.commit();
             //防止内存不够,清理一下
             sqlSession.clearCache();
         }
     }
      //预防漏数据,最后再提交一次
     sqlSession.clearCache();
     sqlSession.commit();
     long c2 = System.currentTimeMillis();
     logger.info("处理excel花了:"+(end-start)/1000+"秒");
     logger.info("本次执行过程共"+count+"条数据,花了"+(c2-c1)/1000+"秒");
     logger.info("本次导入共,花了"+(c2-start)/1000+"秒,精准时间"+(c2-start)+"毫秒");
 }catch (Exception e){
     e.printStackTrace();
     //手动回滚异常
     TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     sqlSession.rollback();
 }finally {
     sqlSession.close();
 }
Logo

一站式 AI 云服务平台

更多推荐