搶微信紅包的時(shí)候我們都知道:一個(gè)紅包一旦你搶過之后,以后無論你點(diǎn)多少次都是一樣的結(jié)果。紅包會(huì)提示你已經(jīng)搶過此紅包,而不會(huì)讓你再搶一次。
創(chuàng)新互聯(lián)建站主要從事做網(wǎng)站、成都做網(wǎng)站、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)寧安,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
搶紅包接口就是一個(gè)非常典型的冪等接口,搶一次和搶多次具有一樣的效果。類似的接口在我們的開發(fā)過程中會(huì)有很多,比如在電商的下單過程中:
訂單創(chuàng)建接口,第一次調(diào)用返回超時(shí)了,重試機(jī)制一般會(huì)再次調(diào)用這個(gè)接口,此時(shí)我們不能因?yàn)檫@個(gè)接口被調(diào)了兩次就創(chuàng)建兩個(gè)一樣的訂單;
庫存扣減接口,支付接口也是類似的邏輯;
今天的文章就來講講什么是接口的冪等性,并介紹幾種實(shí)現(xiàn)接口冪等性的方案。
冪等原先是數(shù)學(xué)中的一個(gè)概念,表示進(jìn)行1次變換和進(jìn)行N次變換產(chǎn)生的效果相同。
當(dāng)我們討論接口的冪等性時(shí)一般是在說:
以相同的請(qǐng)求調(diào)用這個(gè)接口一次和調(diào)用這個(gè)接口多次,對(duì)系統(tǒng)產(chǎn)生的影響是相同的。如果一個(gè)接口滿足這個(gè)特性,那么我們就說這個(gè)
接口是一個(gè)冪等接口。比如上面的搶紅包接口。
PS:這邊順帶說下冪等和防止重復(fù)提交的區(qū)別。
防止重復(fù)提交更多的是不讓用戶發(fā)起多次一樣的請(qǐng)求。比如說用戶在線購(gòu)物下單時(shí)點(diǎn)了提交訂單按鈕,但是由于網(wǎng)絡(luò)原因響應(yīng)很慢,此時(shí)用戶比較心急多次點(diǎn)擊了訂單提交按鈕。
這種情況下就可能會(huì)造成多次下單。一般防止重復(fù)提交的方案有:將訂單按鈕置灰,跳轉(zhuǎn)到結(jié)果頁等。主要還是從客戶端的角度來解決這個(gè)問題。
冪等更多的是在重復(fù)請(qǐng)求已經(jīng)發(fā)生,或是無法避免的情況下,采取一定的技術(shù)手段讓這些重復(fù)請(qǐng)求不給系統(tǒng)帶來副作用。
并不是所有接口都需要保證冪等性。以相同的請(qǐng)求調(diào)用這個(gè)接口一次或多次,需要給調(diào)用方返回一致的結(jié)果時(shí),就要考慮將這個(gè)接口設(shè)計(jì)成冪等接口。
在我們?cè)O(shè)計(jì)冪等接口時(shí)重點(diǎn)關(guān)注新增接口和更新接口。因?yàn)椴樵兒蛣h除操作天生是冪等的(根據(jù)id查詢和根據(jù)id刪除多次對(duì)系統(tǒng)的影響是一致的),不需要我們提供額外的
技術(shù)手段來保證冪等性。(??)
對(duì)于新增和更新接口,大致有以下幾種方案可以保證接口冪等性。
這是一種比較好理解,通用的方案。
當(dāng)調(diào)用接口時(shí),參數(shù)中必須傳入
source
字段和
seq
字段(這邊舉了一個(gè)我們項(xiàng)目中的列子,其實(shí)并不一定要傳兩個(gè)字段,傳一個(gè)唯一的序列號(hào)uuid也能達(dá)到一樣的效果)。服務(wù)端接收到請(qǐng)求,先判斷自己是否是一個(gè)冪等接口,如果不是冪等接口就正常處理請(qǐng)求。
如果是一個(gè)冪等接口,就將
source
和
seq
組成聯(lián)合主鍵去數(shù)據(jù)庫表中或者是redis中查詢,如果沒有查詢到,說明沒處理過這個(gè)請(qǐng)求,然后正常處理請(qǐng)求就行了。處理完之后將處理結(jié)果和
source
和
seq
信息一個(gè)存入數(shù)據(jù)庫或Redis中。
如果根據(jù)
source
和
seq
能查詢到,說明已經(jīng)處理過這個(gè)請(qǐng)求了,直接將處理的結(jié)果返回即可。
我們發(fā)現(xiàn)這種方案非常簡(jiǎn)單,而且易于理解,通用。但是如果請(qǐng)求量很大的話,存放請(qǐng)求記錄的表會(huì)很大,這個(gè)時(shí)候可以將一段時(shí)間之前的記錄刪除,以提升性能。
這種方案適合用于執(zhí)行新增操作的接口。
比如說新增用戶接口。我們將用戶表中的身份證字段加上唯一索引。當(dāng)同一個(gè)請(qǐng)求調(diào)用兩次時(shí),我們可以先根據(jù)身份證字段查詢下用戶是否存在,不存在的話再新增。存在的話就返回新增失敗。
或者直接新增也行,數(shù)據(jù)庫會(huì)拋異常,我們對(duì)異常處理返回前臺(tái)就行了。
PS:大家可能會(huì)有一個(gè)疑問,我同一個(gè)請(qǐng)求調(diào)用兩次,第一返回新增成功,第二次返回失敗,返回的結(jié)果不同啊。這個(gè)接口還是冪等接口么?
這邊我要重申下概念,冪等強(qiáng)調(diào)的是接口一次調(diào)用和多次調(diào)用產(chǎn)生的效果是一樣的。這邊調(diào)用一次和調(diào)用多次都是新增了一個(gè)對(duì)象,所以還是滿足冪等的。
這種方案適用于執(zhí)行更新操作的接口。
樂觀鎖只是在更新數(shù)據(jù)那一刻鎖表,其他時(shí)間不鎖表,所以相對(duì)于悲觀鎖,效率更高。 我們一般通過數(shù)據(jù)庫來實(shí)現(xiàn)樂觀鎖,比較通用的做法是增加一個(gè)時(shí)間戳字段。
Copyupdate table_xxx set name=#name#, timestamp = now where id=#id# and timestamp=#timestamp# --這個(gè)值由前端到數(shù)據(jù)中查詢出來,再傳過來