环境:SpringBoot,MybatisPlus
之前项目中遇到过批量查询数据,由于数据量过大,且调用了多处查询接口,且有调用三方平台接口,于是使用了多线程并行执行,大大提高了效率。
在此为了学习加深印象,再次尝试实现一下多线程的批量入库操作。
实现逻辑:
1,创建线程池;
2,定义一个批量插入数据库的方法,并用@Async 注解标注。
3,拿到要批量入库的数据,分割成多个数据块。
4,然后将分隔后的数据块分别调用入库方法。
- 先创建一个线程池的配置。在需要异步执行的方法上添加@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;
}
}
- 创建接口方法并在方法上添加 @Async 注解。
public interface ISStockService extends IService<SStock> {
//批量插入List
@Async
void batchSaveList(List list);
}
- 实现该方法后,在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!";
}