一、幂等的数学概念
- 一元计算中,x为某集合的任意数,如果满足f(x)=f(f(x)),则称f运算具有幂等性。
比如绝对值abs(a)=abs(abs(a))为幂等函数 - 二元运算,x为集合任意数,如果f(x,x)=x,则称f运算也有幂等性。
比如max(x,x)=x也幂等函数
二、幂等在开发中的概念
- 同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,则称此操作是幂等的。
- 要求幂等例子:微信支付,一笔订单应当只扣一次钱,那么无论网络等原因导致重新付款,都只能扣一次
三、HTTP协议与幂等性
-查询操作(GET):幂等。GET用于获取资源,不对资源进行改变。注意幂等体现在对系统资源的改变,而不是返回数据的结果。
- 删除操作(DELETE):幂等。虽然改变了资源,但第一次和第N次删除操作对系统的作用是相同的。(虽然第一次返回200,N-1次返回404)
- 修改操作(PUT):幂等。PUT协议只能做固定的操作,比如修改账号金额为1000元,而不是账户中减少50.只是在第一次改了,N-1次都是重复操作,资源不会再变
- 新增操作(POST):非幂等。POST用请求实体来创建新的资源。幂等需要业务中实现。
参考:https://restfulapi.net/idempotent-rest-apis/
四、实现幂等性的方案
- 去重表:利用数据库的特性来实现幂等。通常是在表上构建一个唯一索引,那么只要某一个数据构建完毕,后面再次操作也无法成功写入。
适用于在业务中有唯一标识的插入场景。比如订单支付中,订单ID可以作为唯一标识作为唯一索引,将支付数据写入去重表中。从而导致第二次以后无法插入表单。 - 乐观锁(版本控制):只是更新为固定值,没必要加锁。加锁是在资源不固定,例如账户金额减少50元这种情况。
UPDATE tab1 SET col1=col-1,version=version+1 WHERE id=#id# and version=#version#
乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表, - token:后端生成token给前端,前端提交把token给后端进行一致性校验;若一致,则删除token;若前端再提交,后端token已删除,则不一致,避免了重复提交。
此时token何时生成就成为关键:在用户提交时生成,则每次都是新token,不是幂等问题。在博客中,用户进入编辑页面,则要生成token。 Token 生成的时机必须保证能够使该操作具多次执行都是相同的效果才行。
在Session原理中有涉及 - 状态标识:一般用于业务流程较长,修改数据较多场景中。比如“创建订单 -> 订单支付\取消 -> 账户计算 -> 通知商户“”,当做完一个步骤就修改对应的状态标识。
- 支付缓冲区:把订单的支付请求都快速地接下来,一个快速接单的缓冲管道。后续使用异步任务处理管道中的数据,过滤掉重复的待支付订单。优点是同步转异步,高吞吐量。缺点是不能及时地返回支付结果,需要后续监听支付结果的异步返回