最近做項目,關於訂單創建時候因為需要調用遠程http服務獲取數據,然后校驗並寫入數據庫和修改數據庫,
導致接口效率低,所以想到實現異步操作的方式解決。
在調用遠程接口成功的時候即認為接口處理成功,返回給前段正確,並開啟線程進行數據的寫入和修改
1)添加配置類
1 package com.fieldsales.pos.config; 2 3 import lombok.Data; 4 import org.springframework.boot.context.properties.ConfigurationProperties; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.scheduling.annotation.EnableAsync; 8 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 9 10 import java.util.concurrent.Executor; 11 import java.util.concurrent.ThreadPoolExecutor; 12 13 /** 14 * @author :CX 15 * @Date :Create in 2019/3/29 10:42 16 * @Effect :線程池配置類 17 */ 18 @Configuration 19 @EnableAsync 20 @ConfigurationProperties(prefix = "async") 21 @Data 22 public class ExecutorConfig { 23 24 private int corePoolSize; 25 private int maxPoolSize; 26 private int queueCapacity; 27 private String namePrefix; 28 29 30 @Bean(name = "asyncServiceExecutor") 31 public Executor asyncServiceExecutor() { 32 System.err.println("初始化線程池-----"); 33 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 34 //配置核心線程數 35 executor.setCorePoolSize(corePoolSize); 36 //配置最大線程數 37 executor.setMaxPoolSize(maxPoolSize); 38 //配置隊列大小 39 executor.setQueueCapacity(queueCapacity); 40 //配置線程池中的線程的名稱前綴 41 executor.setThreadNamePrefix(namePrefix); 42 43 // rejection-policy:當pool已經達到max size的時候,如何處理新任務 44 // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行 45 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 46 //執行初始化 47 executor.initialize(); 48 return executor; 49 } 50 51 52 }
2)在配置文件中添加相應配置
1 #線程池配置 2 async: 3 # 配置核心線程數 4 corePoolSize: 30 5 # 配置最大線程數 6 maxPoolSize: 30 7 # 配置隊列大小 8 queueCapacity: 9999 9 # 配置線程池中的線程的名稱前綴 10 namePrefix: async-createOrderService-
3) 注入使用
1 //注入線程池 2 @Autowired 3 private Executor asyncServiceExecutor; 4 5 //上方代碼接口調用成功 略 6 // 開啟線程寫入數據庫數據 7 asyncServiceExecutor.execute(new Runnable() { 8 @Override 9 public void run() { 10 11 //標記數據是否正常寫入 , 如果數據寫入數據庫異常,則每10S寫出一次異常日志 12 boolean isAddOrder = false; 13 // 數據寫入的時間 14 String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(new Date()); 15 16 try{ 17 //開啟事物寫入數據 18 } catch (Throwable throwable) { 19 // 接口成功但是寫入數據失敗,則間隔拋出異常 20 while (true) { 21 logger.error("嚴重錯誤------------------------------------------------------------"); 22 logger.error("訂單【" + resultdata.get("orderno").toString() + "】銷售成功,但寫入現場售票數據庫失敗!"); 23 logger.error("詳情表: :" + JSON.toJSONString(orderInfos)); 24 logger.error("訂單表:" + JSON.toJSONString(tkttransFormModel)); 25 logger.error("異常信息:" + throwable.getMessage()); 26 logger.error("錯誤時間:" + format); 27 try { 28 Thread.sleep(20000); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 } 33 } 34 } 35 }); 36 return HSResponse.ok(responsMap);