本篇博文是「Java秒殺系統實戰系列文章」的第十一篇,本篇博文咱們將藉助定時任務調度組件來輔助「失效超時未支付的訂單記錄」的處理,用以解決上篇博文中採用「RabbitMQ死信隊列失效處理超時未支付的訂單」的瑕疵!java
上篇文章咱們介紹瞭如何採用消息中間件RabbitMQ的死信隊列失效處理超時未支付的訂單,實戰完畢以後,相信各位小夥伴對死信隊列應該有了一個初步的認識以及使用。在該業務場景中,雖然死信隊列能夠「近乎完美」地解決那樣的需求,可是卻仍然存在着一點瑕疵,即 「當許多訂單記錄剛好在某個TTL集中失效,準備交由RabbitMQ的死信隊列進行處理時,此時剛好RabbitMQ的服務掛掉了。。。」git
RabbitMQ的服務忽然掛掉,將意味着在那個時候那些本該被失效處理的訂單記錄卻遲遲沒有獲得處理(由於RabbitMQ已經不提供服務了!),雖而後面重啓了RabbitMQ服務,消息也從新進行了處理,可是卻有可能在這段時間內用戶「從新下不了單」或者其餘一些意想不到的問題!數據庫
各位小夥伴看到這裏,估計應該明白個大概了!雖然會抱怨「他孃的,平白無故,RabbitMQ的服務咋會掛掉」!抱怨歸抱怨,現實卻仍舊是現實,隱患仍然是存在的,那既然存在隱患,那就得找尋一些方法來解決。bash
本篇博文咱們將採用「定時器」或者叫「定時任務調度」的方式來輔助處理,即咱們會設定一下Cron時間,定時在數據庫中輪詢獲取status=0(即狀態爲未支付)的訂單,並更新失效掉那些時間已經超過了TTL的訂單!(set status=-1)。下面咱們進入代碼實戰環節:服務器
(1)定時器的實現咱們暫且採用一個比較簡單的方式,即@Scheduled註解來實現,咱們將全部的簡單定時器的實現都放在SchedulerService服務類中,其完整源代碼以下所示:微信
@Service
public class SchedulerService {
private static final Logger log= LoggerFactory.getLogger(SchedulerService.class);
@Autowired
private ItemKillSuccessMapper itemKillSuccessMapper;
@Autowired
private Environment env;
//定時獲取status=0的訂單並判斷是否超過TTL,而後進行失效
@Scheduled(cron = "0 0/30 * * * ?")
public void schedulerExpireOrders(){
try {
List<ItemKillSuccess> list=itemKillSuccessMapper.selectExpireOrders();
if (list!=null && !list.isEmpty()){
//java8的寫法
list.stream().forEach(i -> {
if (i!=null && i.getDiffTime() > env.getProperty("scheduler.expire.orders.time",Integer.class)){
itemKillSuccessMapper.expireOrder(i.getCode());
}
});
}
}catch (Exception e){
log.error("定時獲取status=0的訂單並判斷是否超過TTL,而後進行失效-發生異常:",e.fillInStackTrace());
}
}
}複製代碼
其中的遍歷,Debug是採用了Java8的Steam API。上述這種定時任務調度的寫法簡單粗暴,並且還快!(世上武功無堅不摧、無快不破!)可是,快歸快,在這裏仍是須要提一點注意的地方。多線程
(2)即若是在該項目有多個這樣的定時任務,那麼有一點值得注意的是:多個定時任務的執行時間Cron若是捱得很近,那麼效率必定是瓶頸,這是由於若是隻是上面那樣寫,那麼始終只會有一個、單一的線程在執行上面的定時任務!app
試想一下,若是有定時任務A、B、C都是每隔5分鐘執行一次,那麼很明顯,將會有一些定時任務處於阻塞的狀態而遲遲不能在規定的時間內執行完!ide
所以,爲了解決此種「痛點」,咱們須要加入一些自定義的配置,即針對「定時任務調度」咱們加入「線程池」的配置,其完整的源代碼以下所示,各位小夥伴能夠寫多幾個定時器,而後觀察控制檯的輸出信息,便可看到每一個不一樣的定時任務採用了不一樣的線程執行。ui
/**
* 定時任務多線程處理的通用化配置
* @Author:debug (SteadyJack)
* @Date: 2019/6/29 21:45
**/
@Configuration
public class SchedulerConfig implements SchedulingConfigurer{
//針對定時任務調度-配置多線程(線程池)
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
複製代碼
(3)至此,關於定時任務輔助失效處理秒殺系統中「超時未支付的訂單記錄」的代碼已經實戰完畢了!能夠調整一下Cron的取值,而後將整個系統運行在外置的Tomcat服務器,稍等片刻便可看到定時任務的執行了,在這裏就不貼圖了!
一、目前,這一秒殺系統的總體構建與代碼實戰已經所有完成了,完整的源代碼數據庫地址能夠來這裏下載:gitee.com/steadyjack/… 記得Fork跟Star啊!!
二、最後,不要忘記了關注一下Debug的技術微信公衆號: