SpringBoot 利用 ThreadPoolTaskExecutor 批量插入数十万条数据

这篇具有很好参考价值的文章主要介绍了SpringBoot 利用 ThreadPoolTaskExecutor 批量插入数十万条数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot 利用 ThreadPoolTaskExecutor 批量插入万条数据

在批处理插入数据时,如果在单线程环境下是非常耗时的,本篇文章将采用单线程和多线程进行对比,利用 ThreadPoolTaskExecutor 进行多线程批处理插入65w数据,然后和单线程进行对比,最终得到性能优化。

springboot并发10万,Java,spring boot,java,spring,压力测试

springboot并发10万,Java,spring boot,java,spring,压力测试

yml 文件配置

# 异步线程池配置
thread:
  pool:
    corePoolSize: 8 # 核心线程数
    maxPoolSize: 20 # 设置最大线程数
    keepAliveSeconds: 300 # 设置线程活跃时间
    queueCapacity: 100 # 设置队列容量
    prefixName: async-service- # 线程名称前缀

spring 容器注入线程池 bean 对象

@Data
@ConfigurationProperties(prefix = "thread.pool")
public class ThreadPoolConfig {
    /**
     * 核心线程数
     */
    private Integer corePoolSize;

    /**
     * 设置最大线程数
     */
    private Integer maxPoolSize;

    /**
     * 设置线程活跃时间
     */
    private Integer keepAliveSeconds;

    /**
     * 设置队列容量
     */
    private Integer queueCapacity;

    /**
     * 线程名称前缀
     */
    private String prefixName;
}
@Configuration
@EnableAsync
@Slf4j
public class ThreadPoolExecutorConfig {
    private ThreadPoolConfig threadPoolConfig;

    public ThreadPoolExecutorConfig(ThreadPoolConfig threadPoolConfig) {
        this.threadPoolConfig = threadPoolConfig;
    }

    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(threadPoolConfig.getCorePoolSize());
        executor.setMaxPoolSize(threadPoolConfig.getMaxPoolSize());
        executor.setQueueCapacity(threadPoolConfig.getQueueCapacity());
        executor.setKeepAliveSeconds(threadPoolConfig.getKeepAliveSeconds());
        executor.setThreadNamePrefix(threadPoolConfig.getPrefixName());
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}

创建异步线程业务类

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {
    @Override
    @Async("asyncServiceExecutor")
    public void executeAsync(List<StandardStation> list, StandardStationService standardStationService, CountDownLatch countDownLatch) {
        try {
            log.info("start executeAsync");
            // 异步线程需要做的事情
            standardStationService.saveBatch(list);
            log.info("end executeAsync");
        } finally {
            // 无论上面程序是否异常必须执行 countDown,否则 await 无法释放
            countDownLatch.countDown();
        }
    }
}

创建单线程批量插入具体业务方法

/**
 * 单线程插入 650000 条数据
 */
@Test
public void testSingleThread() {
    // 10000 条数据
    List<StandardStation> standardStationList = list.stream().map(info -> {
        StandardStation standardStation = new StandardStation();
        BeanUtils.copyProperties(info, standardStation);
        return standardStation;
    }).collect(Collectors.toList());
    // 单线程 每 100 条数据插入一次
    List<List<StandardStation>> lists = Lists.partition(standardStationList, 100);
    long startTime = System.currentTimeMillis();
    lists.forEach(listSub -> standardStationService.saveBatch(listSub));
    long endTime = System.currentTimeMillis();
    log.info("共耗时:{} 秒", (endTime - startTime) / 1000);
}

结果:

springboot并发10万,Java,spring boot,java,spring,压力测试

创建多线程批量插入具体业务方法

/**
 * 多线程插入 650000 条数据
 */
@Test
public void testMultiThread() {
    // 10000 条数据
    List<StandardStation> standardStationList = list.stream().map(info -> {
        StandardStation standardStation = new StandardStation();
        BeanUtils.copyProperties(info, standardStation);
        return standardStation;
    }).collect(Collectors.toList());
    // 每 100 条数据插入开一个线程
    List<List<StandardStation>> lists = Lists.partition(standardStationList, 100);
    CountDownLatch countDownLatch = new CountDownLatch(lists.size());
    long startTime = System.currentTimeMillis();
    lists.forEach(listSub -> asyncService.executeAsync(listSub, standardStationService, countDownLatch));
    try {
        // 保证之前的所有的线程都执行完成,才会走下面的
        countDownLatch.await();
    } catch (InterruptedException e) {
        log.error("阻塞异常:" + e.getMessage());
    }
    long endTime = System.currentTimeMillis();
    log.info("共耗时:{} 秒", (endTime - startTime) / 1000);
}

结果:

springboot并发10万,Java,spring boot,java,spring,压力测试

从上述的结果可以看出,使用多线程后,批处理插入大量数据的耗时大大减少,由此可见多线程的好处。文章来源地址https://www.toymoban.com/news/detail-626246.html

到了这里,关于SpringBoot 利用 ThreadPoolTaskExecutor 批量插入数十万条数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表

    SpringBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表  更多优秀文章,请扫码关注个人微信公众号或搜索“ 程序猿小杨 ”添加。 一、背景         因业务发展需要,需要对接kafka,快速批量接收消息日志,避免消息日志累积过多,必须做到数据处理后,动态

    2024年02月10日
    浏览(26)
  • SpringBoot+MyBatis批量插入数据的三种方式

    最近导入表格数据时需要同时插入修改大量数据,研究了一下有三种实现方式 1、用for循环调用sql插入数据 这种方式插入大量数据时,效率非常底下,不推荐 2、利用mybatis的foreach来实现循环插入 这种方式插入大量数据时,好处是不用频繁访问数据库,一条sql搞定,效率比较

    2024年02月16日
    浏览(29)
  • 13 秒插入 30 万条数据,我惊呆了!

    本文主要讲述通过MyBatis、JDBC等做大数据量数据插入的案例和结果。 实体类、mapper和配置文件定义 User实体 mapper接口 mapper.xml文件 jdbc.properties sqlMapConfig.xml 不分批次直接梭哈 循环逐条插入 MyBatis实现插入30万条数据 JDBC实现插入30万条数据 总结 验证的数据库表结构如下: 话不

    2024年02月11日
    浏览(38)
  • 如何往MySQL中插入100万条数据?

    现在有一个 数据量 为100万的数据样本 100w_data.sql 其数据格式如下,截取最后十条数据 999991,XxGdnLZObA999991,XxGdnLZObA,XxGdnLZObA,2020-3-18,1 999992,TBBchSKobC999992,TBBchSKobC,TBBchSKobC,2020-9-8,2 999993,rfwgLkYhUz999993,rfwgLkYhUz,rfwgLkYhUz,2020-2-6,0 999994,GQZXukHouW999994,GQZXukHouW,GQZXukHouW,2020-9-16,1 999995,UMNjgaXtn

    2024年02月15日
    浏览(25)
  • Java怎么实现几十万条同时数据插入(三种基本方法测试)

    目录 1,使用批量插入  2,使用多线程 3,使用存储过程 在Java中实现插入几十万条数据,有多种方法可以使用。以下是其中的几种: 使用批量插入可以有效地提高插入速度。下面是一个示例代码: 使用多线程可以将数据分为多个部分并行插入,提高效率。以下是一个示例代

    2024年02月14日
    浏览(31)
  • springboot使用aop排除某些方法,更新从另外一张表,从另外一张表批量插入

    在Spring Boot中使用AOP时,如果想要排除某些方法不被切面所影响,可以通过使用切面表达式中的!within来实现。以下是一个示例: 在上面的示例中,@Before注解用于定义切面的beforeAdvice方法。execution(* com.example.service. . (…))表示切入所有com.example.service包下的方法。而!wit

    2024年02月13日
    浏览(34)
  • springboot自帶线程池ThreadPoolTaskExecutor使用

        不管是阿里,还是华为java开发手册,都会有一条建议,就是让开发者不要使用Executors去创建线程池,而是使用构造函数ThreadPoolExecutor的方式来创建,并设置合理的参数。原因如下:      说明:Executors 返回的线程池对象的弊端如下: 1) FixedThreadPool 和 SingleThreadPool: 允

    2024年02月04日
    浏览(28)
  • SpringBoot多线程异步任务:ThreadPoolTaskExecutor + CompletableFuture

    在 SpringBoot 项目中,一个任务比较复杂,执行时间比较长,需要采用 多线程异步 的方式执行,从而缩短任务执行时间。 将任务拆分成多个独立的子任务,每个子任务在独立子线程中执行; 当所有子任务的子线程全部执行完成后,将几个子任务汇总,得到总任务的执行结果。

    2024年02月10日
    浏览(43)
  • MySQL——插入加锁/唯一索引插入死锁/批量插入效率

    本篇主要介绍MySQL跟加锁相关的一些概念、MySQL执行插入Insert时的加锁过程、唯一索引下批量插入可能导致的死锁情况,以及分别从业务角度和MySQL配置角度介绍提升批量插入的效率的方法; 在介绍MySQL执行插入的加锁过程之前,先复习下几种跟锁相关的概念; 快照读 InnoDB 利

    2024年02月12日
    浏览(30)
  • Mybatis 中传入List实现 批量插入、批量更新、批量删除

    个人收藏使用 文章来自Mybatis 中传入List实现 批量插入、批量更新、批量删除 - chelsey3tsf - 博客园 (cnblogs.com) 1. 批量插入 : Mapper层: 对应的mapper.xml: 如果List数据量比较大,可以考虑将List分批次插入 2. 批量更新: 批量更新只提供更新单个字段的,因为更新多个字段无论哪种

    2024年02月11日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包