訂單重復(fù)問題已經(jīng)是老生常談的問題了卓嫂,我們熟悉的淘寶購物流程榔昔,購物車-->生成訂單--》提交訂單--》訂單確認(rèn)--》支付訂單--》備貨--》發(fā)貨,這里可能會(huì)有一些問題定硝,例如皿桑,有人惡意或者無意的重復(fù)提交訂單,從而導(dǎo)致數(shù)據(jù)庫保存的訂單數(shù)量與實(shí)際不符蔬啡,重復(fù)提交訂單導(dǎo)致用戶體驗(yàn)不佳诲侮,甚至更為嚴(yán)重的是,用戶重復(fù)支付了同一個(gè)訂單箱蟆。所以沟绪,涉及到訂單,應(yīng)該首先想清楚如何設(shè)計(jì)才能保證系統(tǒng)不會(huì)出現(xiàn)這些問題
如何防止訂單重復(fù)提交
首先說兩個(gè)我們購物時(shí)經(jīng)常有過的體驗(yàn)或者說購物網(wǎng)站的網(wǎng)頁提醒
- 你提交的動(dòng)作過快空猜,請(qǐng)稍后嘗試
- 你的訂單已經(jīng)超時(shí)绽慈,請(qǐng)刷新頁面后重新提交
看到這些提示,說明該購物網(wǎng)站做了訂單提交的限制辈毯,一方面是防止有人惡意無限制提交訂單坝疼,所以限制了一定時(shí)間內(nèi)最大可操作次數(shù),另一方面是為了保證訂單無重復(fù)提交谆沃。那么這是怎么做到的呢钝凶?
第一個(gè)應(yīng)該比較簡(jiǎn)單,限制某個(gè)時(shí)間內(nèi)的最大操作次數(shù)只需要有一個(gè)計(jì)數(shù)器就可以唁影,計(jì)數(shù)器可以用redis實(shí)現(xiàn)耕陷,設(shè)置一個(gè)帶有有效時(shí)間的值作為計(jì)數(shù)器,如果值不存在則自動(dòng)創(chuàng)建据沈,超過某一個(gè)值就認(rèn)為操作次數(shù)用完即可以實(shí)現(xiàn)啃炸。
第二個(gè)可以使用token機(jī)制,token即令牌卓舵,學(xué)過spring security的相信對(duì)這個(gè)詞不會(huì)陌生南用。我們可以使用類似spring security的機(jī)制在頁面上生成一個(gè)token,當(dāng)提交訂單時(shí),根據(jù)該token的有效時(shí)間和允許的使用次數(shù)來判斷訂單是否允許提交裹虫,從而規(guī)避重復(fù)提交的問題肿嘲。當(dāng)然,有人會(huì)問筑公,在高并發(fā)的情況下雳窟,如果是判斷token有效之前有很多同一個(gè)用戶的提交線程過來(用戶正常使用一般不會(huì)出現(xiàn)這種情況,一般是壓力測(cè)試工具導(dǎo)致的)匣屡,那么還是會(huì)重復(fù)提交封救,所以,這里需要用到鎖機(jī)制捣作,訪問同一個(gè)用戶的token同一時(shí)間只能有一個(gè)線程誉结,token使用之后失效了就會(huì)被清掉,之后的線程就找不到該token券躁,從而認(rèn)為訂單不能提交惩坑。
訂單確認(rèn)支付
如支付寶和微信等,支付寶和微信本身是怎么限制訂單只能支付一次的呢也拜?訂單怎么保證只會(huì)被支付一次呢以舒?這個(gè)問題相對(duì)來說就簡(jiǎn)單很多了,同一訂單的狀態(tài)更新的SQL只需要帶上條件慢哈,利用的是數(shù)據(jù)庫的行鎖蔓钟。當(dāng)然,如果是分布式系統(tǒng)卵贱,這里涉及到的問題會(huì)更多滥沫。
update table item set item.status=:newstatus where item.id = :id and item.status = oldstatus.
對(duì)比案例
-
美團(tuán)GTIS
主要看GTIS的流程圖以及想想其交易ID的作用,交易之前艰赞,后臺(tái)會(huì)返回一個(gè)交易ID給前端佣谐,前端在點(diǎn)擊交易按鈕時(shí)需將該交易ID和其他交易信息同時(shí)返回給后臺(tái)進(jìn)行處理肚吏,通過全局的交易ID實(shí)現(xiàn)“該次交易的”冪等性image
參考資料和研究
- 分布式鎖的對(duì)比分析:非常好的一篇文章方妖,包含下面的關(guān)鍵詞:可重入、阻塞罚攀、公平党觅、排他、樂觀斋泄、悲觀杯瞻、單點(diǎn)、死鎖發(fā)生炫掐、連接池狀況魁莉、實(shí)現(xiàn)種類、實(shí)現(xiàn)方式
轉(zhuǎn)載:http://www.reibang.com/p/530228b71888