前言
- 開發目的: 提高百萬級數據插入效率。
-
采取方案: 利用
ThreadPoolTaskExecutor
多線程批量插入。 - 采用技術: springboot2.1.1+mybatisPlus3.0.6+swagger2.5.0+Lombok1.18.4+postgresql+ThreadPoolTaskExecutor等。
基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
具體實現細節
application-dev.properties
添加線程池配置信息
> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
>
> * 項目地址:
> * 視頻教程:
# 異步線程配置
# 配置核心線程數
async.executor.thread.core_pool_size = 30
# 配置最大線程數
async.executor.thread.max_pool_size = 30
# 配置隊列大小
async.executor.thread.queue_capacity = 99988
# 配置線程池中的線程的名稱前綴
async.executor.thread.name.prefix = async-importDB-
spring容器注入線程池bean對象
@Configuration
@EnableAsync
@Slf4j
publicclassExecutorConfig{
@Value("${async.executor.thread.core_pool_size}")
privateintcorePoolSize;
@Value("${async.executor.thread.max_pool_size}")
privateintmaxPoolSize;
@Value("${async.executor.thread.queue_capacity}")
privateintqueueCapacity;
@Value("${async.executor.thread.name.prefix}")
privateStringnamePrefix;
@Bean(name="asyncServiceExecutor")
publicExecutorasyncServiceExecutor(){
log.warn("startasyncServiceExecutor");
//在這里修改
ThreadPoolTaskExecutorexecutor=newVisiableThreadPoolTaskExecutor();
//配置核心線程數
executor.setCorePoolSize(corePoolSize);
//配置最大線程數
executor.setMaxPoolSize(maxPoolSize);
//配置隊列大小
executor.setQueueCapacity(queueCapacity);
//配置線程池中的線程的名稱前綴
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:當pool已經達到max size的時候,如何處理新任務
// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());
//執行初始化
executor.initialize();
returnexecutor;
}
}
創建異步線程 業務類
@Service
@Slf4j
publicclassAsyncServiceImplimplementsAsyncService{
@Override
@Async("asyncServiceExecutor")
publicvoidexecuteAsync(ListlogOutputResults,LogOutputResultMapperlogOutputResultMapper,CountDownLatchcountDownLatch) {
try{
log.warn("startexecuteAsync");
//異步線程要做的事情
logOutputResultMapper.addLogOutputResultBatch(logOutputResults);
log.warn("endexecuteAsync");
}finally{
countDownLatch.countDown();//很關鍵,無論上面程序是否異常必須執行countDown,否則await無法釋放
}
}
}
創建多線程批量插入具體業務方法
@Override
publicinttestMultiThread(){
ListlogOutputResults=getTestData();
//測試每100條數據插入開一個線程
List>lists=ConvertHandler.splitList(logOutputResults,100);
CountDownLatchcountDownLatch=newCountDownLatch(lists.size());
for(ListlistSub:lists){
asyncService.executeAsync(listSub,logOutputResultMapper,countDownLatch);
}
try{
countDownLatch.await();//保證之前的所有的線程都執行完成,才會走下面的;
//這樣就可以在下面拿到所有線程執行完的集合結果
}catch(Exceptione){
log.error("阻塞異常:"+e.getMessage());
}
returnlogOutputResults.size();
}
模擬2000003 條數據進行測試
多線程 測試 2000003 耗時如下:耗時1.67分鐘
本次開啟30個線程,截圖如下:
單線程測試2000003 耗時如下:耗時5.75分鐘
檢查多線程入庫的數據,檢查是否存在重復入庫的問題:
根據id分組,查看是否有id重復的數據,通過sql語句檢查,沒有發現重復入庫的問題
檢查數據完整性:通過sql語句查詢,多線程錄入數據完整
測試結果
不同線程數測試:
總結
通過以上測試案列,同樣是導入2000003 條數據,多線程耗時1.67分鐘,單線程耗時5.75分鐘。通過對不同線程數的測試,發現不是線程數越多越好,具體多少合適,網上有一個不成文的算法:
CPU核心數量*2
+2 個線程。
附:測試電腦配置
審核編輯 :李倩
-
SQL
+關注
關注
1文章
773瀏覽量
44219 -
多線程
+關注
關注
0文章
278瀏覽量
20053 -
spring
+關注
關注
0文章
340瀏覽量
14369 -
SpringBoot
+關注
關注
0文章
174瀏覽量
194
原文標題:性能爆表:SpringBoot利用ThreadPoolTaskExecutor批量插入百萬級數據實測!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論