无处不在的幂等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

相关文章
相关标签/搜索