SpringBoot 使用线程池 实现 批量插入数据到Mysql

环境:SpringBoot,MybatisPlus

之前项目中遇到过批量查询数据,由于数据量过大,且调用了多处查询接口,且有调用三方平台接口,于是使用了多线程并行执行,大大提高了效率。
在此为了学习加深印象,再次尝试实现一下多线程的批量入库操作。

实现逻辑:
1,创建线程池;
2,定义一个批量插入数据库的方法,并用@Async 注解标注。
3,拿到要批量入库的数据,分割成多个数据块。
4,然后将分隔后的数据块分别调用入库方法。

1. 先创建一个线程池的配置。在需要异步执行的方法上添加@Async 注解进行标注;(参照博客:创建线程池配置是为了不影响主线程,异步方法交给单独的线程完成;)

@Configuration//声明当前类是配置类
@EnableAsync//开启异步调用(该注解也可以放在springboot启动类上)
public class ExecutorConfig {
    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

    private static final int COREPOOLSIZE = 5;
    private static final int MAXPOOLSIZE = 5;
    private static final int QUEUECAPACITY = 20;
    private static final String NAMEPREFIX = "async-service-";
	@Bean
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(10);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("hello Thread-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

2. 创建接口方法并在方法上添加 @Async 注解。

public interface ISStockService extends IService<SStock> {
    //批量插入List
    @Async
    void batchSaveList(List list);
}

3. 实现该方法后,在controller 中分割数据后分别进行调用。

@GetMapping("/saveData")
    @Transactional(rollbackFor = Exception.class)
    public String saveData() throws Exception {
		
		//... 省略获取数据
		//... 这里是我需要去入库的数据,此处为jsonArray 格式
        JSONArray diff = data.getJSONArray("diff");

		//处理数据,将数据切分成多个,多线程并发执行插入操作。
        int count = 10000;                   //一个线程处理300条数据
        int listSize = diff.size();        //数据集合大小
        int runSize = (listSize/count)+1;  //开启的线程数
        List<Object> newlist = null;       //存放每个线程的执行数据
        //使用的线程数
        for (int i = 0; i < runSize; i++) {
            if((i+1)==runSize){
                int startIndex = (i*count);
                int endIndex = diff.size();
                newlist = diff.subList(startIndex,endIndex);
            }else{
                int startIndex = (i*count);
                int endIndex = (i+1)*count;
                newlist= diff.subList(startIndex, endIndex);
            }
            //service 中实现的用@Async 注解标注的插入方法
            stockService.batchSaveList(newlist);
        }
        return "SUCESS!";
    }

Over…

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,针对您的问题,我可以给您提供以下的代码片段作为参考: 首先,您需要在您的 Spring Boot 项目中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> ``` 然后,在您的应用程序配置文件(例如 `application.properties` 或 `application.yml`)中添加以下配置: ```yaml spring.datasource.url=jdbc:mysql://localhost:3306/testdb spring.datasource.username=root spring.datasource.password=123456 # 线程池配置 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=60000 spring.datasource.hikari.pool-name=MyHikariCP ``` 在您的代码中,您可以使用 `JdbcTemplate` 来执行数据库操作,并使用 `ThreadPoolTaskExecutor` 来并发地执行多个任务。例如: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import javax.sql.DataSource; @Configuration public class AppConfig { @Autowired private DataSource dataSource; @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource); } @Bean public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.setThreadNamePrefix("MyThread-"); executor.initialize(); return executor; } } ``` 然后,您可以编写一个方法来并发地执行多个任务,例如: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; @Service public class MyService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private ThreadPoolTaskExecutor taskExecutor; public void insertDataConcurrently() { for (int i = 0; i < 10; i++) { taskExecutor.execute(() -> { jdbcTemplate.update("insert into my_table (column1, column2) values (?, ?)", "value1", "value2"); }); } } } ``` 在上述代码中,我们使用 `taskExecutor.execute()` 方法来提交一个任务,这个任务会被分配到线程池中的一个线程来执行。每个任务都会执行一个插入操作,将一行数据插入到数据库表中。 希望这个代码片段能够对您有所帮助!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值