Spring Boot分段处理List集合多线程批量插入数据

news/2024/5/16 1:32:06

项目场景:

大数据量的List集合,需要把List集合中的数据批量插入数据库中。


解决方案:

拆分list集合后,然后使用多线程批量插入数据库

1.实体类

package com.test.entity;import lombok.Data;@Data
public class TestEntity {private String id;private String name;
}

2.Mapper

如果数据量不大,用foreach标签就足够了。如果数据量很大,建议使用batch模式。

package com.test.mapper;import java.util.List;import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;import com.test.entity.TestEntity;public interface TestMapper {/*** 1.用于使用batch模式,ExecutorType.BATCH开启批处理模式* 数据量很大,推荐这种方式*/@Insert("insert into test(id, name) "+ " values"+ " (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR})")void testInsert(TestEntity testEntity);/*** 2.使用foreach标签,批量保存* 数据量少可以使用这种方式*/@Insert("insert into test(id, name) "+ " values"+ " <foreach collection='list' item='item' index='index' separator=','>"+ " (#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR})"+ " </foreach>")void testBatchInsert(@Param("list") List<TestEntity> list);
}

3.spring容器注入线程池bean对象

package com.test.config;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
@EnableAsync
public class ExecutorConfig {/*** 异步任务自定义线程池*/@Bean(name = "asyncServiceExecutor")public Executor asyncServiceExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//配置核心线程数executor.setCorePoolSize(50);//配置最大线程数executor.setMaxPoolSize(500);//配置队列大小executor.setQueueCapacity(300);//配置线程池中的线程的名称前缀executor.setThreadNamePrefix("testExecutor-");// rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//调用shutdown()方法时等待所有的任务完成后再关闭executor.setWaitForTasksToCompleteOnShutdown(true);//等待所有任务完成后的最大等待时间executor.setAwaitTerminationSeconds(60);return executor;}
}

4.创建异步线程业务类

package com.test.service;import java.util.List;
import java.util.concurrent.CountDownLatch;import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import com.test.entity.TestEntity;
import com.test.mapper.TestMapper;@Service
public class AsyncService {@Autowiredprivate SqlSessionFactory sqlSessionFactory;@Async("asyncServiceExecutor")public void executeAsync(List<String> logOutputResults, CountDownLatch countDownLatch) {try{//获取session,打开批处理,因为是多线程,所以每个线程都要开启一个事务SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);TestMapper mapper = session.getMapper(TestMapper.class);//异步线程要做的事情for (int i = 0; i < logOutputResults.size(); i++) {System.out.println(Thread.currentThread().getName() + "线程:" + logOutputResults.get(i));TestEntity test = new TestEntity();//test.set()//.............//批量保存mapper.testInsert(test);//每1000条提交一次防止内存溢出if(i%1000==0){session.flushStatements();}}//提交剩下未处理的事务session.flushStatements();}finally {countDownLatch.countDown();// 很关键, 无论上面程序是否异常必须执行countDown,否则await无法释放}}
}

5.拆分list调用异步的业务方法

package com.test.service;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;import javax.annotation.Resource;import org.springframework.stereotype.Service;@Service
public class TestService {@Resourceprivate AsyncService asyncService;public int testMultiThread() {List<String> logOutputResults = getTestData();//按线程数拆分后的listList<List<String>> lists = splitList(logOutputResults);CountDownLatch countDownLatch = new CountDownLatch(lists.size());for (List<String> listSub:lists) {asyncService.executeAsync(listSub, countDownLatch);}try {countDownLatch.await(); //保证之前的所有的线程都执行完成,才会走下面的;// 这样就可以在下面拿到所有线程执行完的集合结果} catch (Exception e) {e.printStackTrace();}return logOutputResults.size();}public List<String> getTestData() {List<String> logOutputResults = new ArrayList<String>();for (int i = 0; i < 3000; i++) {logOutputResults.add("测试数据"+i);}return logOutputResults;}public List<List<String>> splitList(List<String> logOutputResults) {List<List<String>> results = new ArrayList<List<String>>();/*动态线程数方式*/// 每500条数据开启一条线程int threadSize = 500;// 总数据条数int dataSize = logOutputResults.size();// 线程数,动态生成int threadNum = dataSize / threadSize + 1;/*固定线程数方式// 线程数int threadNum = 6;// 总数据条数int dataSize = logOutputResults.size();// 每一条线程处理多少条数据int threadSize = dataSize / (threadNum - 1);*/// 定义标记,过滤threadNum为整数boolean special = dataSize % threadSize == 0;List<String> cutList = null;// 确定每条线程的数据for (int i = 0; i < threadNum; i++) {if (i == threadNum - 1) {if (special) {break;}cutList = logOutputResults.subList(threadSize * i, dataSize);} else {cutList = logOutputResults.subList(threadSize * i, threadSize * (i + 1));}results.add(cutList);}return results;}
}

5.Controller测试

@RestController
public class TestController {@Resourceprivate TestService testService;@RequestMapping(value = "/log", method = RequestMethod.GET)@ApiOperation(value = "测试")public String test() {testService.testMultiThread();return "success";}
}

总结:

注意这里执行插入的数据是无序的。

Java多线程分段处理List集合_java 每个list分配一个线程-CSDN博客 


http://www.mrgr.cn/p/05345285

相关文章

Linux内核源码-存储驱动之 QSPI Flash

传输方式 DIO/QIO/DOUT/QPIQPI模式(Quad Peripheral Interface),所有阶段都通过4线传输。与之相对的是SPI。 SPI模式:纯种SPI(MISO/MOSI两个数据线) DOUT 全称 Dual I/O,命令字和地址字均为单线,仅在数据阶段为双线。 QOUT 全称 Quad I/O,命令字和地址字均为单线,仅在数据…

求极限的方法总结

求极限的方法总结 两个重要极限: \(\Large \underset{x\rightarrow 0}{\lim}\frac{\sin x}{x} = 1\) \(\Large \underset{x\rightarrow \infty}{\lim}(1+\frac{1}{x})^x=e\) 1. 直接代入 函数在某点连续,函数在该点的极限等于该点的函数值 一切初等函数在其定义区间内都是连续…

VPN的基本概念

随着互联网的普及和应用的广泛&#xff0c;网络安全和隐私保护越来越受到人们的关注。在这个信息爆炸的时代&#xff0c;我们的个人信息、数据通信可能会受到各种威胁&#xff0c;如何保护自己的隐私和数据安全成为了一个迫切的问题。而VPN&#xff08;Virtual Private Network…

Windows下绑定线程到指定的CPU核心

在某些场景下,需要把程序绑定到指定CPU核心提高执行效率。通过微软官方文档查询到Windows提供了两个Win32函数:SetThreadAffinityMask和SetProcessAffinityMask 为指定线程和进程设置处理器关联掩码。通俗的讲就是在指定的CPU核心上执行线程或者进程。这里的CPU核心指的是逻辑…

Web前端安全问题分类综合以及XSS、CSRF、SQL注入、DoS/DDoS攻击、会话劫持、点击劫持等详解,增强生产安全意识

前端安全问题是指发生在浏览器、单页面应用、Web页面等前端环境中的各类安全隐患。Web前端作为与用户直接交互的界面&#xff0c;其安全性问题直接关系到用户体验和数据安全。近年来&#xff0c;随着前端技术的快速发展&#xff0c;Web前端安全问题也日益凸显。因此&#xff0c…

环境安装:python环境迁移(无网和有网)

前言 环境部署或迁移是一项简单而又考验应对能力的一项工作&#xff0c;需要考虑到网络环境的情况&#xff0c;无网环境下需要采取离线方式进行操作&#xff0c;有网环境则可以直接通过在线安装完成。 在进行Python环境迁移时&#xff0c;需要注意保持环境的一致性&#xff0c;…

html-docx-js 导出word

1:列表页面按钮<el-button type="warning" plain icon="el-icon-download" size="mini" @click="exportWorddata" >导出word</el-button>…

vue2集成ElementUI编写登录页面

目录 1. 整理目录文件&#xff1a; a. app.vue文件如下&#xff1a; b. Login.vue文件如下&#xff1a; c. router/index.js文件如下&#xff1a; d. 删除components中的文件&#xff1a; e. 最终项目目录整理如下&#xff1a; 2. 集成ElementUI编写登录页面 a. 安装El…

notepadd++下载

现在网上下载个软件越来越麻烦了,各种广告各种隐藏陷阱。 为了大家以后能更快速的下载到正版的notepad++ 这里上传到git做了备份下载地址 : https://gitee.com/liu_chaos/notepad-8.5.3-official-version/blob/master/Notepad_downloader.8.5.3.exe本文来自博客园,作者:lan…

AI视频分析技术的常用开源模型及TSINGSEE青犀AI视频识别分析能力介绍

AI视频分析技术是指利用人工智能技术来对视频数据进行分析和处理的技术。开源模型是指可以免费获取和使用的代码模型&#xff0c;可以帮助开发人员快速构建和部署AI视频分析应用程序。 以下是一些业内常用的用于AI视频分析技术的开源模型&#xff1a; OpenCV&#xff1a;Open…

【稳定检索|投稿优惠】2024年应用数学、建模与计算机工程国际会议(IASAMCE 2024)

2024 International Conference on Applied Mathematics, Modeling, and Computer Engineering 一、大会信息 会议名称&#xff1a;2024年应用数学、建模与计算机工程国际会议 会议简称&#xff1a;IASAMCE 2024 收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Schola…

linux安装selenium步骤

1,安装selenium模块pip3 install selenium2,安装谷歌浏览器yum install https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm -y3安装chromedriver1)运行下面命令查看浏览器版本google-chrome --version 出现这个代表谷歌浏览器安装成功 2)谷歌浏览…

tada68键盘的设置

一、到网址:https://config.qmk.fm/,选择tada68 二、选择键位层,设置键位时可从键位码直接拖拽即可,此处设计0键位层,键位是:此处设计1键位层,键位是:键位码:三、设置好了,可以编译了,点击右上角的编译图标编译过程会出来一个大土豆旋转,直到出现:Checking file s…

Spring AI 抢先体验,5 分钟玩转 Java AI 应用开发

Spring Cloud Alibaba AI 以 Spring AI 为基础,并在此基础上提供阿里云通义系列大模型全面适配,让用户在 5 分钟内开发基于通义大模型的 Java AI 应用。作者:刘军 Spring AI 是 Spring 官方社区项目,旨在简化 Java AI 应用程序开发,让 Java 开发者像使用 Spring 开发普通应…

GPT的全面历史和演变:从GPT-1到GPT-4

人工智能新篇章&#xff1a;GPT-4与人类互动的未来&#xff01; 本文探讨了生成式预训练 Transformer (GPT) 的显着演变&#xff0c;提供了从开创性的 GPT-1 到复杂的 GPT-4 的旅程。 每次迭代都标志着重大的技术飞跃&#xff0c;深刻影响人工智能领域以及我们与技术的互动。 我…

开发工具IDEA

IDEA个人使用偏好,笔记。图居多,文字少,可自行参考(个人使用版本:2021.2.2)由于某些原因限制,所以不解释为什么还不更新使用新版本,可自行检索,答案很少,但存在即合理。有疑问可私信! 下载 步骤: 进官网 官网,https://www.jetbrains.com.cn/ 切换语言选择工具进入…

将针孔模型相机 应用到3DGS

Motivation 3DGS 的 投影采用的是 CG系的投影矩阵 P P P, 默认相机的 principal point (相机光心) 位于图像的中点处。但是 实际应用的 绝大多数的 相机 并不满足这样一个设定&#xff0c; 因此我们 需要根据 f , c x , c y {f,c_x, c_y} f,cx​,cy​ 这几个参数重新构建3D …

IDEA Plugins:Show Comment(快捷显示注释)安装及使用

感谢友情分享此插件的同学--夏生 简介 Show doc comment at the Project view Tree, line End, json, other 在文件树、行末、JSON 等地方显示注释. 说明 强制依赖被引用字段、方法等的注释,若是被引用的对象没有注释,则不会显示 效果下载安装插件:Ctrl+Alt+S 搜索Plugins,…

IDEA Plugins:Show Comment 代码行后快捷显示注释

感谢友情分享此插件的同学--夏生 简介 Show doc comment at the Project view Tree, line End, json, other 在文件树、行末、JSON 等地方显示注释. 说明 强制依赖被引用字段、方法等的注释,若是被引用的对象没有注释,则不会显示 效果下载安装插件:Ctrl+Alt+S 搜索Plugins,…

Window 安装 Python 失败 0x80070643,发生严重错误

问题现象 用安装包在 window 安装python,会遇到没有安装成功,卸载后,再次双击安装包安装的时候,直接无法安装了。 这个问题在github issue中有提到,但是都是 2022 年的时,代码修复,但是在 2024 年,安装的时候还是遇到了这个问题。 测试下来:python 3.7, 3.8 没有这个问…