老婆问了个问题,什么是“幂等性”?这个问题,从现象上好解释,例如今儿是618大促,购物车添加了丰富的商品,满心欢喜地点击了支付按钮,支付成 功了,但是返回的时候网络异常,不知道是不是扣款成功了,实际上在服务端货款已经扣了,此时再点击支付按钮,如果第二次扣款成功,则就是多扣钱了,如果第 二次扣款不成功,符合我们的预期,说明这个支付的功能,满足“幂等性”。
从理论上讲,HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
从上面定义看,关注以下几个点:
1.幂等不仅仅只是一次(或多次)请求对资源没有副作用。
2.幂等还包括第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
3.幂等关注的是以后的多次请求是否对资源产生的副作用,而不关注结果。
4.网络超时等问题,不是幂等的讨论范围。
在分布式环境下,系统之间不同服务的相互调用,需要关注幂等性的设计,幂等性是系统服务对外一种承诺(而不是实现),承诺只要调用接口成功,外部多次调用对系统的影响是一致的,声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试。
在 概念上,幂等和防重,还是有些区别。重复提交是在第一次请求已经成功的情况下,人为的进行多次操作,导致不满足幂等要求的服务多次改变状态。而幂等更多使 用的情况是第一次请求不知道结果(例如网络异常)或者失败的异常情况下,发起多次请求,目的是多次确认第一次请求成功,却不会因多次请求而出现多次的状态 变化。听着有些绕口,关键是他们的初衷不同,防重是明知成功还要做,幂等是未知结果还要做。
对于数据库增删改查的操作,不同的操作,不同的场景,对于幂等性,会是不同的满足,
1. 查询操作,是天然的幂等,例如select a from t where c=1,无论执行多少次都不会改变状态。
2. 删除操作,一般情况下,多次请求的结果,是相同的,只会删除一次。
3. 修改操作,不同场景,结果可能不多,
例如update t set c=2 where d=1,无论执行多少次,状态都是一致的,符合幂等性。
例如update t set c=c+1 where d=1,每次执行的结果,都会发生变化,这是非幂等的。
4. 插入操作,重复提交,如果业务逻辑上未作判断,则会插入多条,不符合幂等性。
如果服务端符合幂等性,其实是增加了服务端的设计复杂度,简化了客户端的处理逻辑。满足幂等服务的,毕竟需要查询上一次的执行状态,如果没有则认为是第一次请求,并且在服务改变状态的业务逻辑前,存在保证防重复提交的逻辑。
关于幂等性设计的实现,有不少的方法,例如乐观锁、分布式锁、token令牌等,各位可以从网络上得到借鉴,此处不再赘述。
作为吃瓜群众,尤其像支付场景,必须支持幂等,否则先崩溃的可能不是系统,而是我们自己。