一. 概念
对于同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,就称该操作为幂等的
举例:
- 博客系统同一个用户对同一个文章点赞,即使这人单身30年手速疯狂按点赞,那么实际上也只能给这个文章 +1 赞
- 在微信支付的时候,一笔订单应当只能扣一次钱,那么无论是网络问题或者bug等而重新付款,都只应该扣一次钱
二. 数据库增删改查
操作 | 是否冥等 | 表述 |
---|---|---|
查询操作(Get) | ✅ | 返回结果不相同但是该操作本身没有副作用,所以幂等 |
删除操作(Delete) | ✅ | 第一次和第N次删除操作对系统的作用是相同的 |
修改操作(Put) | 资源固定的情况下是冥等 | 账户中金额减少50元 这种操作在Put协议中是不允许的,只能做类似于 账户中金额改为 1000 元 的操作 |
新增操作(Post) | ❌ | 每次调用都会在系统中产生新的资源 |
三. 实战
1. 去重表
利用数据库的特性来实现幂等。通常是在表上构建一个唯一索引,那么只要某一个数据构建完毕,后面再次操作也无法成功写入
2. 状态标识
状态标识是很常见的幂等设计方式,主要思路就是通过状态标识的变更,保证业务中每个流程只会在对应的状态下执行,如果标识已经进入下一个状态,这时候来了上一个状态的操作就不允许变更状态,保证了业务的幂等性
医药电商:
状态标识经常用在业务流程较长,修改数据较多的场景里。最经典的例子就是订单系统,假如一个订单要经历 创建订单 -> 订单支付\取消 -> 账户计算 -> 通知商户 这四个步骤。那么就有可能一笔订单支付完成后去账户里扣除对应的余额,消耗对应的优惠卷。但是由于网络等原因返回了错误信息,这时候就会重试再次去进行账户计算步骤造成数据错误。
所以为了保证整个订单流程的幂等性,可以在订单信息中增加一个状态标识,一旦完成了一个步骤就修改对应的状态标识。比如订单支付成功后,就把订单标识为修改为支付成功,现在再次调用订单支付或者取消接口,会先判断订单状态标识,如果是已经支付过或者取消订单,就不会再次支付了。
3. Token 机制
Token 机制应该是适用范围最广泛的一种幂等设计方案了,具体实现方式也很多样化。但是核心思想就是每次操作都生成一个唯一 Token 凭证,服务器通过这个唯一凭证保证同样的操作不会被执行两次。这个 Token 除了字面形式上的唯一字符串,也可以是多个标志的组合(比如上面提到的状态标志),甚至可以是时间段标识等等。