無處不在的冪等f(f(x)) = f(x)

冪等的基本概念

可能咱們常常在看網上文章的時候會看到冪等這個概念,那麼冪等究竟是什麼呢?面試

冪等:在編碼中談的冪等通常對應數學概念中的一元冪等:某一元運算爲冪等的時,其做用在任一元素兩次後會和其做用一次的結果相同 f(f(x)) = f(x)。既 對於同一個輸入無論進行多少次函數運算都應該都應該獲得相同的結果

不堪回首的往事

在一次偶然的bug的發現了冪等這個概念的重要性。實際業務是這樣的。數據庫

作一個訂單銷售額的統計:每次有訂單付款成功的時候會通知一個統計接口,統計接口中則累計當天的訂單總金額。

大概代碼以下:函數

type Order struct {
    Id int
    Price int
    Sn string
    Date time.Time
}
func settle(info Order)  {
    //get day price
    dayPrice := 20
    price := info.Price
    dayPrice += price
    //save to databases
    return
}

上面的代碼看起來是沒問題的。可是當相同的訂單重複調用這個接口的時候就會出現訂單金額重複計算的問題。最後就獲得一個優化的方案。優化

type Order struct {
    Id int
    Price int
    Sn string
    Date time.Time
    SettleStatus int
}

func settle(info Order)  {
    //check order settle status
    if info.SettleStatus !=1 {
        return
    }
    //get day price
    dayPrice := 20
    price := info.Price
    dayPrice += price
    //save to databases

    //update order status
    info.SettleStatus = 2
    //save to databases

    return
}

在統計金額修改以前去判斷當前訂單是否被統計過了,這樣就避免了重複統計。編碼

這是一個最簡單的冪等思想的應用。

10塊錢的麻辣燙

之前在網上看到過這麼一個面試題。spa

這裏有3我的共同擁有10塊錢,在他們同時使用這十塊錢買東西的時候,怎麼保證不被超用。
  • 常見的解決方案就是加鎖,每次使用扣費以前都去獲取一個鎖,搶到鎖的人優先使用這十塊錢。
  • 若是用冪等的思想的話。咱們能夠在使用以前先獲取到當前的餘額,在最後扣費的時候判斷當前的餘額是不是開始獲取的那個餘額。
func pay()  {
    //查詢當前可用金額 select money from table
    money := 3
    //買一隻筆花了2塊錢
    money = 1

    //update databases
    //修改數據庫的時候判斷條件是否爲開始獲取的金額,若是不是,那麼消費失敗,或者進入重試流程
    // update table set money=1 where money = 3

}

MQ中的重複通知

在MQ通知中咱們常常會遇到消息會重複通知的問題。這個時候爲了保證數據的準確性,咱們也常常會用到冪等的思想。
MQ重複消息處理一般有兩種方式。
  • 在消息中加入一個消息惟一標識,在消費的時候判斷消息是否被消費過了,若是已經被消費,那麼直接確認消費成功,若是沒有被消費,那麼執行消費的邏輯,而後將消息ID入庫,用於下次判斷。
  • 在消費端處理業務邏輯的時候使用冪等的處理方式,保證無論來多少次最後處理的結果都是同樣的。
這些簡單的例子均可以說明冪等的在編碼中的重要性,其實還有不少地方都在使用冪等的思想。寫這個東西並非教你們怎麼去使用冪等,而是忽然以爲咱們在編碼的時候儘可能多思考,也許只是一個很小的改動就能拯救你的代碼,多思考,多利用一些成熟的方式來,保證代碼的質量,提升本身的思惟嚴謹性。

歡迎一塊兒交流

file

相關文章
相關標籤/搜索