需求:在每次線下活動的開始的前一天晚上七點給報名參加價值研習社的用戶發一條通知短信用戶記得準時參加活動。html
備註:由於咱們的業務併發不是很大,因此不少場景並無考慮到併發狀況下的一些問題,這個需求正好經過crontab執行,而且加上服務器的自動彈性伸縮,因此至關於模擬了一次併發的業務場景。mysql
先簡單介紹一下數據庫的表結構:sql
這幾個方案都依賴天天晚上七點執行一次corntab。數據庫
根據開講時間查詢活動表是否有知足條件的線下活動,若是有的話,再經過活動id關聯到簽到表過濾出send_sms字段爲0的uid並關聯用戶表拿出手機號等信息。發送完成後再統一更新send_sms字段。服務器
缺點:在併發業務場景下,可能會產生髒讀的狀況,形成發送屢次短信的狀況。併發
與方案1很類似,惟一的區別就是查詢的時候開啓事務用SELECT ... FOR UPDATE ,這種查詢語句的區別就是在SELECT
的時候把結果行上鎖,從而就能避免髒讀,而後再同一個事務中UPDATE
send_sms字段,最後commit
。ui
缺點:因爲發短信不是數據庫操做,不可回滾。因此若是執行的過程當中發生回滾,就會出現短信已經發出去了,可是數據庫發生回滾,send_sms字段置爲了0,這就產生了矛盾。並且若是是個耗時的任務可能會出現死鎖的問題。spa
BEGIN;
SELECT ... FOR UPDATE;
UPDATE ... SET send_sms = 1;
COMMIT;
複製代碼
與方案2很類似,惟一的區別就是一條一條的取數據上鎖,而後更新send_sms
字段。code
缺點:要寫一個循環一直去查詢知足條件但還未發送短信的用戶。處理很差容易產生死循環以及死鎖的問題。cdn
這是我目前能想到的最佳方案,直接用SELECT
語句選出全部知足條件的手機號碼以及短信內容,放入Queue
中,而後實現對Queue
的處理。處理以下:先用SELECT ... FOR UPDATE
判斷send_sms
字段的值,若是爲0,那就執行發短信,而後更新send_sms
字段爲1,最後COMMIT
。這樣就能夠避免屢次執行發短信。
總結:對於這種對實時性要求沒那麼高的業務場景用Queue
仍是很是便利的,讓Queue
一條一條的處理,在複雜的系統中還起到了削峯和解耦的做用。你們在工做中有哪些對Queue
的應用呢?歡迎留言,一塊兒討論!
你們對上面的這些方案有什麼建議呢?歡迎留言討論!