![](http://static.javashuo.com/static/loading.gif)
介紹
冪等性就是同一個操做執行屢次,產生的效果同樣。如http的get請求,數據庫的select請求就是冪等的前端
在分佈式系統中,保證接口的冪等性很是重要,如提交訂單,扣款等接口都要保證冪等性,否則會形成重複建立訂單,重複扣款,那麼如何保證接口的冪等性呢?mysql
前端保證冪等性的方法
按鈕只能點擊一次web
用戶點擊按鈕後將按鈕置灰,或者顯示loading狀態redis
RPG模式sql
即Post-Redirect-Get,當客戶提交表單後,去執行一個客戶端的重定向,轉到提交成功頁面。避免用戶按F5刷新致使的重複提交,也能消除按瀏覽器後退鍵致使的重複提交問題。目前絕大多數公司都是這樣作的,好比淘寶,京東等數據庫
後端保證冪等性的方法
使用惟一索引後端
對業務惟一的字段加上惟一索引,這樣當數據重複時,插入數據庫會拋異常瀏覽器
狀態機冪等微信
若是業務上須要修改訂單狀態,例如訂單狀態有待支付,支付中,支付成功,支付失敗。設計時最好只支持狀態的單向改變。這樣在更新的時候就能夠加上條件,屢次調用也只會執行一次。例如想把訂單狀態更新爲支持成功,則以前的狀態必須爲支付中併發
update table_name set status = 支付成功 where status = 支付中
樂觀鎖實現冪等
-
查詢數據得到版本號 -
經過版本號去更新,版本號匹配則更新,版本號不匹配則不更新
-- 假如查詢出的version爲1
select version from table_name where userid = 10;
-- 給用戶的帳戶加10
update table_name set money = money -10, version = version + 1 where userid = 10 and version = 1
也能夠經過條件來實現樂觀鎖,如庫存不能超賣,數量不能小於0
update table_name set num = num - 10 where num - 10 >= 0
防重表
增長一個防重表,業務惟一的id做爲惟一索引,如訂單號,當想針對訂單作一系列操做時,能夠向防重表中插入一條記錄,插入成功,執行後續操做,插入失敗,則不執行後續操做。本質上能夠當作是基於MySQL實現的分佈式鎖。根據業務場景決定執行成功後,是否刪除防重表中對應的數據
分佈式鎖實現冪等
執行方法時,先根據業務惟一的id獲取分佈式鎖,獲取成功,則執行,失敗則不執行。分佈式鎖能夠基於redis,zookeeper,mysql來實現,分佈式鎖的細節就不介紹了
select+insert
先查詢一下有沒有符合要求的數據,若是沒有再執行插入。沒有併發的系統中能夠保證冪等性,高併發下不要用這種方法,也會形成數據的重複插入。我通常作消息冪等的時候就是先select,有數據直接返回,沒有數據加分佈式鎖進行insert操做
全局惟一號實現冪等
經過source(來源)+ seq(序列號)來判斷請求是否重複,重複則直接返回請求重複提交,不然執行。如當多個三方系統調用服務的時候,就能夠採用這種方式
![](http://static.javashuo.com/static/loading.gif)
歡迎關注
![](http://static.javashuo.com/static/loading.gif)
有幫助?點贊!轉發!
本文分享自微信公衆號 - Java識堂(erlieStar)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。