实测Java批量导入百万级数据

news2024/12/26 11:54:02

JAVA通过ThreadPoolTaskExecutor批量插入百万级数据


文章目录

  • JAVA通过ThreadPoolTaskExecutor批量插入百万级数据
  • 一、前言
  • 二、实现步骤
    • 1、application.yml添加线程池配置信息
    • 2、业务类,创建多线程批量插入具体业务方法
    • 3、spring容器注入线程池bean对象
    • 4、测试
  • 三、总结


一、前言

百万级数据批量插入数据库,如何提高效率?

采取方案:利用ThreadPoolTaskExecutor多线程批量插入。

采用技术:springboot+mybatisPlus+mysql+ThreadPoolTaskExecutor。


二、实现步骤

直接上代码,代码如下:

1、application.yml添加线程池配置信息

# 异步线程配置
# 配置核心线程数
async:
  executor:
    thread:
      core_pool_size: 4
      max_pool_size: 9
      queue_capacity: 99988
      name:
        prefix: async-importDB-

2、业务类,创建多线程批量插入具体业务方法

@Service
@Slf4j
public class AsyncServiceImpl {

     @Resource
     private PostMapper postMapper;

     /**
      * 生成虚拟数据
      */
     public List<Post> getPostList(){
          List<Post> postList=new ArrayList<>();
          for(int i=1;i<=2000003;i++){
               Post post=new Post();
               post.setPostId((long) i);
               post.setPostCode("code_"+i);
               post.setPostName("name_"+i);
               post.setPostSort(String.valueOf(i));
               post.setStatus("0");
               postList.add(post);
          }
          return postList;
     }

     /**
      * 开启多线程
      * @param list 每个批次的数据
      * @param countDownLatch  Java 中的一个并发工具类,用于协调多个线程之间的同步
      */
     @Async("asyncServiceExecutor")
     public void executeAsync(List<Post> list,CountDownLatch countDownLatch) {
          try{
               log.warn("start executeAsync");
               //异步线程要做的事情
               //批量新增插入数据库
               postMapper.batchPost(list);
               log.warn("end executeAsync");
          }finally {
               countDownLatch.countDown();// 很关键, 无论上面程序是否异常必须执行countDown,否则await无法释放
          }
     }

     /**
      * 执行业务
      */
     public void testMultiThread() {
          List<Post> logOutputResults = getPostList();
          Date start=DateUtils.getNowDate();
          //测试每1000条数据插入开一个线程
          List<List<Post>> lists = groupList(logOutputResults, 1000);
          CountDownLatch countDownLatch = new CountDownLatch(lists.size());
          for (List<Post> listSub:lists) {
               //分批次执行数据
               executeAsync(listSub,countDownLatch);
          }
          try {
               countDownLatch.await(); //保证之前的所有的线程都执行完成,才会走下面的;
               // 这样就可以在下面拿到所有线程执行完的集合结果
          } catch (Exception e) {
               log.error("阻塞异常:"+e.getMessage());
          }
          Date end=DateUtils.getNowDate();
          System.out.println("导入消耗时间"+DateUtils.getDatePoor(end,start));
     }

     /**
      * 根据每个线程执行的数量拆分成多个数组
      * @param list 所有数据
      * @param size 拆分每个批次数量
      */
     public List<List<Post>> groupList(List<Post> list, int size) {
          List<List<Post>> resList=new ArrayList<>();
          int totalBatches = (int) Math.ceil((double) list.size()/ size);
          for (int i = 0; i < totalBatches; i++) {
               int startIndex = i * size;
               int endIndex = Math.min((i + 1) * size, list.size());
               List<Post> batch = list.subList(startIndex, endIndex);
               resList.add(batch);
          }
          return resList;
     }

     /**
      * 计算两个时间差
      */
     public static String getDatePoor(Date endDate, Date nowDate) {
          long nd = 1000 * 24 * 60 * 60;
          long nh = 1000 * 60 * 60;
          long nm = 1000 * 60;
          long ns = 1000;
          // 获得两个时间的毫秒时间差异
          long diff = endDate.getTime() - nowDate.getTime();
          // 计算差多少天
          long day = diff / nd;
          // 计算差多少小时
          long hour = diff % nd / nh;
          // 计算差多少分钟
          long min = diff % nd % nh / nm;
          // 计算差多少秒//输出结果
          long sec = diff % nd % nh % nm / ns;
          return day + "天" + hour + "小时" + min + "分钟" + sec + "秒";
     }

     public static void main(String[] args) {
          testMultiThread();
     }
}

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

代码如下(示例):

@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;

    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.warn("start asyncServiceExecutor");
        //在这里修改
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

4、测试

模拟2000003 条数据进行测试。
在这里插入图片描述

检查多线程入库的数据,检查是否存在重复入库的问题:

根据id分组,查看是否有id重复的数据,通过sql语句检查,没有发现重复入库的问题
在这里插入图片描述

三、总结

通过以上测试案列,同样是导入2000003 条数据,多线程耗时1.67分钟,单线程耗时15.38分钟。
这里使用线程数量计算公式:CPU核心数量*2 +1个线程。我的电脑是4核16G,所以设定线程数是9个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode:13. 罗马数字转整数(python3解法)

难度&#xff1a;简单 罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M …

C/S架构的医学影像PACS系统源码,应用于放射、超声、内窥镜、病理等影像科室

C/S架构的PACS系统&#xff0c;采用DICOM3.0国际标准设计&#xff0c;以大型关系型数据库作为数据和图像的存储管理工具&#xff0c;是集医学影像的采集、传输、存储、查询、诊断、报告、综合信息管理等于一体的综合应用系统。 系统主要进行病人信息和影像的获取、处理、存储、…

windows10录屏神器,轻松保存高光时刻

录制电脑屏幕成了人们日常生活中经常需要面对的任务&#xff0c;无论是为了制作教程、保存游戏精彩瞬间&#xff0c;还是为了录制在线会议&#xff0c;一个功能强大、简单易用的录屏软件成为人们的迫切需求。在Windows 10操作系统下&#xff0c;有多种录屏方法可供选择。本文将…

如何查看苹果手机电池健康情况?快速查询方法来了!

使用苹果手机的小伙伴们&#xff0c;你们是否关心自己手机的电池健康状况&#xff1f;想随时掌握电池的使用状态&#xff0c;却不知道在哪里查看&#xff1f;本文将为大家提供有关苹果手机电池健康的简单查询方法&#xff0c;让您能够随时随地轻松掌握手机电池的健康状况。 操作…

sqlite3.NotSupportedError: deterministic=True requires SQLite 3.8.3 or higher

问题描述 sqlite3.NotSupportedError: deterministicTrue requires SQLite 3.8.3 or higher 解决方法 A kind of solution is changing the database from sqlite3 to pysqlite3. After acticate the virtualenv, install pysqlite. pip3 install pysqlite3 pip3 install …

CS免杀姿势

一&#xff1a;环境 1.公网vps一台 2.Cobalt Strike 4.7 3.免杀脚本 二&#xff1a;生成payload 生成一个payload c格式的x64位payload 三&#xff1a;免杀 下载免杀脚本 .c打开是这样的 把双引号里面的内容复制出来&#xff0c;放到脚本目录下的1.txt 运行生成器.…

刹车过电压保护

肖特基漏电流大&#xff0c;电池供电能省则省 最好是RCD缓冲&#xff0c;二极管要用快恢复 可以直接连&#xff0c;隔离可以用光耦或者逻辑门 问题4选的三极管Qg太大 问题九选的mos管Rdson太大 要并快恢复

蓝桥杯每日一题203.11.7

题目描述 题目分析 使用dp思维&#xff0c;当前位置是否可行是有上一位置推来&#xff0c;计算出最大的可行位置即可 #include <stdio.h> #include <string.h>#define N 256 int f(const char* s1, const char* s2) {int a[N][N];int len1 strlen(s1);int len2 …

如何在Python爬虫中使用IP代理以避免反爬虫机制

目录 前言 一、IP代理的使用 1. 什么是IP代理&#xff1f; 2. 如何获取IP代理&#xff1f; 3. 如何使用IP代理&#xff1f; 4. 如何避免IP代理失效&#xff1f; 5. 代理IP的匿名性 二、代码示例 总结 前言 在进行爬虫时&#xff0c;我们很容易会遇到反爬虫机制。网站…

不同对话分支的生成展示

第一个分支 第二个分支 生成过程 苏州有几个区 curl -H content-type: application/json -H Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTk1OTM5MzYsInVzZXJfaWQiOiI2In0.MkYG3nBcR-ROHvARpEfnWiw-Jsplap73qEeDn-L7v8I -d {"model"…

Flutter利用GridView创建网格布局实现优美布局

文章目录 简介使用详解导入依赖项创建一个基本的 GridView一些参数说明使用GridView.count来构造 其他控制总结 简介 GridView 是 Flutter 中用于创建网格布局的强大小部件。它允许你在行和列中排列子小部件&#xff0c;非常适合显示大量项目&#xff0c;例如图像、文本、卡片…

LiveMedia支持海康大华GB28181语音对讲需要的设备及服务准备

1、背景 GB28181支持国标协议的设备&#xff0c;通过GB28181注册接入到国标视频平台后。视频平台在某些情况下需要喊话摄像头&#xff0c;LiveMedia视频监控平台支持这样的国标设备语音对讲。就是可以从控制中心和您关注的设备间&#xff0c;进行语音对讲。 2、准备 2.1、准…

3D打印服务展示预约小程序的效果如何

3D打印服务的需求度非常高&#xff0c;同时还有加工、设计等&#xff0c;很多情况下商家需要推广获客及信息展示&#xff0c;而客户也需要多渠道寻找服务订购或咨询等。而在实际经营&#xff0c;3D打印服务商家也面临多个痛点&#xff1a; 1、品牌宣传拓客难 印刷包装行业除了…

用CHAT写APP的权限需求

今天我们来接触一个关于程序的问题&#xff0c;探索更多知识点 问CHAT&#xff1a;一个nuiapp开发的前端app&#xff0c;一般用户安装的时候&#xff0c;都有什么权限可以获取&#xff1f;有什么权限是牵扯隐私的&#xff1f; NUIApp&#xff08;Native User Interface App&am…

TikTok与老年用户:社交媒体的跨代交流

在数字时代&#xff0c;社交媒体已成为人们沟通、分享和互动的主要平台。然而&#xff0c;社交媒体不再仅仅局限于年轻一代&#xff0c;老年用户也逐渐加入其中。 其中&#xff0c;TikTok是一个引领潮流的短视频社交媒体应用&#xff0c;正在吸引越来越多的老年用户。本文将探…

​​Android平台GB28181历史视音频文件回放规范解读及技术实现

技术背景 在实现GB28181历史视音频文件回放之前&#xff0c;我们已完成了历史视音频文件检索和下载&#xff0c;历史视音频回放&#xff0c;在GB28181平台非常重要&#xff0c;比如执法记录仪等前端设备&#xff0c;默认录像数据存储在前端设备侧&#xff0c;如果需要上传到平…

光模块厂家如何实现千兆和万兆的大规模量产

随着网络需求的不断增长&#xff0c;千兆光模块和万兆光模块成为了网络通信中不可或缺的组件。但是&#xff0c;如何实现这些高速光模块的量产却是厂家们面临的难题。本文将介绍千兆光模块和万兆光模块的生产工艺差异和技术挑战&#xff0c;并探讨厂家如何实现千兆和万兆的大规…

JWT简介 JWT结构 JWT示例 前端添加JWT令牌功能 后端程序

目录 1. JWT简述 1.1 什么是JWT 1.2 为什么使用JWT 1.3 JWT结构 1.4 验证过程 2. JWT示例 2.1 后台程序 2.2 前台加入jwt令牌功能 1. JWT简述 1.1 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准&#xff08;(RFC 7…

44A751101-G01 469-P1-HI-A20-E 489-P5-LO-A20

44A751101-G01 469-P1-HI-A20-E 489-P5-LO-A20 在整合IIoT技术的同时&#xff0c;IT/oT融合实施团队将继续就OT网络与公司网络的隔离、OT网络与互联网的隔离、站点和流程级别的最低权限访问控制以及跨站点通信限制做出决策。与此同时&#xff0c;网络安全领域的专业知识正在发…

C++使用serial串口通信 + ROS2程序示例

目录 一、通信协议二、串口调试工具三、serial库的使用3.1 安装serial3.2 serial的使用3.3 绑定端口 四、串口程序示例 串行接口 &#xff08;Serial Interface&#xff09;简称串口&#xff08;通常指COM接口&#xff09;&#xff0c;是采用串行通信方式的扩展接口&#xff0c…