最近專案裡碰到關於水電煤繳費 出現了賬戶餘額剩餘100元,但同一時間可以成功支付4筆100元訂單的問題.出現這種問題的原因主要在於短時間內前端按鈕操作抖動多次請求的情況.同時後端在判斷賬戶餘額然後下單的過程**現了多執行緒併發的問題。解決這種問題的方法一般是從解決訂單重複提交+防止高併發情況下賬戶餘額為負數的情況解決方案。(類似於商品庫存超賣的解決方案)
一般完整的訂單支付流程是這樣的
1.後端生成訂單編號,前端將訂單編號填充的下單頁面中
2.下單頁面 確認訂單編號對應的下單相關資訊,提交給後端
3.後端首先判斷該筆訂單編號是否提交,未提交判斷賬戶餘額資訊是否夠用,如果夠用下單,不夠用提示前端。如果已提交 提示訂單重複提交.
關鍵在於同一時間下單4筆100元,判斷賬戶餘額到下單修改賬戶餘額存在間隔,只要在此時間段過來的請求都可能發生下單多筆成功但實際賬戶餘額不足以支付的問題.
防止訂單重複提交的技術解決方案
關於防止訂單重複提交的技術解決方案這裡面做了很好的介紹,包含4中解決方案,但前面2種方案因為查詢訂單到插入訂單存在間隔,無論是採用mysql還是快取的方式都會存在問題。所以這裡只把採用唯一索引表+redis計數器的方案使用說明下。因為無論是查詢訂單是否重複提交的判斷是基於資料庫或者快取是否存在該筆訂單編號,如果存在不存在說明沒有重複,插入資料,存在說明已重複無法提交.所以在查詢資料到修改資料庫中間會存在間隔,會出現問題。所以需要利用原子性.如果想更加保險的話,建議通過token令牌的方式,後台建立訂單好的同時建立快取中,新增的時候判斷訂單是否存在,存在才可以提交訂單,邏輯判斷完畢刪除該訂單.後面的相同的訂單因為快取中不存在該訂單號,所以會有問題.
建立唯一索引表:建立根據訂單編號來插入的唯一索引表。不存在插入成功說明未重複,存在說明重複。無法插入 報錯.
redis計數器:訂單進來建立該筆訂單的唯一編號計數器+1.如果大於1說明重複,等於1說明不重複.
實際例子說明
這裡我建立了介面,訂單編號傳過來我就+1,然後判斷訂單編號的數值是否大於1,如果大於1說明重複,等於1說明不重複.主要是用了redis中計數器原子特性.也就是說上乙個操作在完成之前不能有新的操作進來.上例子
@controller
public class testcontroller extends basecontroller
return "hello";
}
jemeter測試高併發條件下 訂單是否會重複提交
可以看到非高併發情況下存在先後順序的情況id=004是未重複返回hello,重複的話返回訂單重複提交的提示的.下面我們來測試一下1000個執行緒該併發的情況下的情況。
下面測試下id=005.高併發500次的情況.
上述的結果看到即使在500個併發情況能夠保證同一筆單子 沒有出現重複提交的情況,配合上token令牌效果更佳.
通過唯一索引表 防止訂單重複提交(但是效率不如redis計數器的方式)
同樣這種方式也可以解決訂單重複提交的問題.
總結來看
防止訂單重複提交的方式多種多樣,主要在於了解市面上主要防止訂單重福提交的方案有哪些,有哪些問題及不足。是否適合當前的業務場景等,畢竟技術是服務於業務的。比如token令牌機制 後端生成訂單號並放入快取,前端提交該訂單資訊時,後端介面判斷是否存在,不存在 說明是首次,刪除快取訂單.存在說明是重複的。這種方式對於要求 不高的業務場景是沒有問題的,如不涉及支付的,因為在高併發情況下,判斷快取訂單到刪除的過程中同樣可能會有其他執行緒同樣判斷了訂單不存在 執行下面的業務流導致問題,並不適用於現在的支付場。所以必須使用可以利用原子特性的避免這種查詢和修改可以並**況的發生,如redis計數器及唯一索引機制 .這樣可以保證在多個執行緒在查詢狀態的時候不會處在其他資料處在修改的階段.
Struts2 防止重複提交
struts2 使用 來檢查表單是否重複提交,它採用同步令牌的方式來實現對表單重複提交的判斷。首先需要在表單中使用 標籤建立乙個新的令牌值,並用你所指定的令牌名把令牌儲存到 session 中。而這個令牌值是隨即產生的經過加密的字串行,不會重複。其次需要為 action 配置 tokeninterc...
struts2防止重複提交
struts2的防止重複提交 也使用到了 token 令牌機制 並且使用到了struts2 的乙個叫token 的過濾器 使用方法 看看我們專案的例子 1.首先在struts的配置檔案中 給你的action 加上 token 過濾器 page user userlist.jsp page succe...
解決支付冪等,訂單重複提交
建立資料庫的唯一約束是目前比較常用解決辦法。在實際的支付業務中,通常把訂單號orderid和請求系統編碼system no 或是請求商戶號merchantno 做為資料庫的聯合唯一約束。保證同樣的訂單在資料庫只有唯一的一條記錄。當有重複資料請求時,應用程式在捕獲此sql異常後,進行回滾 去重表 流水...