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…

你可能感兴趣的:(多线程,经验总结,spring,boot,mysql,java)