赞
踩
一般在做业务的增删改查时,都会遇到大量数据插入的问题。如果数据记录达到几万条时,系统服务在数据入库时会卡的非常难受。如何快速的插入数据呢?
首先,我们都会想到进行批量插入数据,但是批量插入之间也有很大的差异。
本文对比MybatisPlus 自带 saveBatch()方法、SqlSession 批量插入方式、自定义foreach方式、多线程foreach()四种方式:
公共配置
获取数据:
/** * 获取数据 */ private List<FeedbackEmp> getData() { List<FeedbackEmp> list = new ArrayList<>(); FeedbackEmp entity; for (int i = 0; i < 300000; i++) { entity = new FeedbackEmp(); entity.setId(i + ""); entity.setEmpId("0"); } return list; } |
Mapper xml SQL:
<insert id="insertBatch" parameterType="list"> INSERT INTO t_supervise_feedback_emp(c_id,c_feedback_id,c_emp_id) VALUES <foreach collection="list" item="item" separator=","> (#{item.id},#{item.feedbackId},#{item.empId}) </foreach> </insert> |
Spring 配置:
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory"/> <constructor-arg value="BATCH"/> </bean> |
(一)saveBatch()方法
/** * MybatisPlus 自带批量 */ @Test public void addBatch() { try { long start = System.currentTimeMillis(); List<FeedbackEmp> list = this.getData(); feedbackEmpService.saveBatch(list, list.size()); long end = System.currentTimeMillis(); System.out.println("插入耗时:--------------------------" + (start - end) + "--------------------------"); } catch (Exception e) { } } |
(二)SqlSession 批量插入方式
/** * SqlSession 批量 */ @Test public void addSession() { SqlSession sqlSession = null; try { sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false); FeedbackEmpMapper mapper = sqlSession.getMapper(FeedbackEmpMapper.class); long start = System.currentTimeMillis(); List<FeedbackEmp> list = this.getData(); long end = System.currentTimeMillis(); System.out.println("插入耗时:--------------------------" + (start - end) + "--------------------------"); } catch (Exception e) { } finally { if (sqlSession != null) { } } } |
(三)自定义foreach方式
/** * foreach 批量 */ @Test public void addForeach() { try { long start = System.currentTimeMillis(); List<FeedbackEmp> list = this.getData(); feedbackEmpMapper.insertBatch(list); long end = System.currentTimeMillis(); System.out.println("插入耗时:--------------------------" + (start - end) + "--------------------------"); } catch (Exception e) { } } |
(四)多线程foreach
/** * foreach 多线程 */ @Test public void addForeachExecutor() { try { long start = System.currentTimeMillis(); List<FeedbackEmp> list = this.getData(); this.exec(list, 1000); long end = System.currentTimeMillis(); System.out.println("插入耗时:--------------------------" + (start - end) + "--------------------------"); } catch (Exception e) { } } /** * 多线程处理 * * @param list 数据 * @param dealSize 每个线程处理数量 * @throws Exception */ private void exec(List<FeedbackEmp> list, int dealSize) throws Exception { if (!CollectionUtils.isEmpty(list)) { //数据总的大小 int count = list.size(); //每个线程数据集 List<FeedbackEmp> threadList = null; //线程池 int runSize = (count / dealSize) + 1; ThreadPoolExecutor executor = new ThreadPoolExecutor( runSize, 350, 30L, TimeUnit.SECONDS, new SynchronousQueue<>()); //计数器 CountDownLatch countDownLatch = new CountDownLatch(runSize); for (int i = 0; i < runSize; i++) { //计算每个线程执行的数据 int startIndex = (i * dealSize); if ((i + 1) == runSize) { int endIndex = count; threadList = list.subList(startIndex, endIndex); } else { int endIndex = (i + 1) * dealSize; threadList = list.subList(startIndex, endIndex); } //线程任务 MyThread myThread = new MyThread(feedbackEmpMapper, threadList, countDownLatch); } //计数 //关闭线程池 } } /** * 自定义线程 */ class MyThread extends Thread { private FeedbackEmpMapper feedbackEmpMapper; private List<FeedbackEmp> list; private CountDownLatch countDownLatch; MyThread(FeedbackEmpMapper feedbackEmpMapper, List<FeedbackEmp> list, CountDownLatch countDownLatch) { this.feedbackEmpMapper = feedbackEmpMapper; this.list = list; this.countDownLatch = countDownLatch; } @Override public void run() { if (!CollectionUtils.isEmpty(list)) { feedbackEmpMapper.insertBatch(list); } } |
对比结果和结论:
saveBatch()方法 | SqlSession 批量插入方式 | 自定义foreach方式 | 多线程foreach | |
500条 | 5427ms | 394ms | 316ms | --- |
1000条 | 12680ms | 552ms | 467ms | --- |
5000条 | 44951ms | 2408ms | 1613ms | 1744ms |
10000条 | 103219ms | 3447ms | 2435ms | 2164ms |
50000条 | --- | 6038ms | 4530ms | 3969ms |
100000条 | --- | 11930ms | 9731ms | 8335ms |
300000条 | --- | 34280ms | 29446ms | 19507ms |
所以 数据量小的时候建议使用 foreach方式,数据量大的时候使用 多线程foreach方式。如果有更快速的方式请留言,一起学习~
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。