工作中经常会遇到一个事务型接口或者一个事务型方法被调用方重复调用,实际上每次调用的数据都是相同的,有可能是因为网络延迟,客户端点击了多次,也可能是调用方故意而为之,不论是哪种情况,我们都不能让这种重复的操作对我们自己的系统造成不必要的影响。因此,我们需要对于接口和方法做幂等校验。其实幂等过滤一直都贯穿IT行业,只不过现在随着互联网行业的发展,行业内的造词能力和词语引用能力越来越强,幂等被计算机行业正式引用。
幂等性
在数学概念里,幂等是指一次变换和N次变换的结果都相同。而在计算机概念中,幂等是指某一操作执行n次和执行一次所产生的影响是一样的,也就是重复执行这项操作也不会对系统造成改变,比如抢优惠券,每人限制抢一张优惠券,可以使用用户ID+优惠券ID做幂等条件,这样就可以保证每个用户只能抢一张此优惠券。
RESTFul幂等
- GET请求:GET请求属于是非事务型请求,每次请求都不会对系统造成任何影响,所以这类接口本身就符合了幂等性(这里说的是对系统造成影响,而不是说每次调用获取到的数据相同,幂等是针对于系统而非接口)
- DELETE请求:DELETE请求是一个特殊的事务型请求,在调用第一次的时候就已经把数据删除了,所以不论后续再次调用多少次,对系统产生的影响都是一样的,所以DELETE类型的请求本身也是符合幂等性的
- PUT请求:PUT请求是对数据进行修改,理论上对同一URI进行多次PUT操作对整个系统的影响和一次PUT是相同的,但是这要结合接口具体代码实现来考量
- 直接将PUT的数值替换掉原有数据:幂等
- 每次调用都对某个数据递增:非幂等,需要手动幂等
- POST请求:POST是创建资源的事务型请求,每次请求都会创建一份资源,所以多次调用对整个系统产生的影响是不同的,该类型的请求是非幂等的
常用幂等方法
-
数据库唯一索引去重
利用数据库唯一索引的特性达到幂等的效果,不会往数据表中插入两条幂等字段相同的数据。例如文章点赞功能,为了防止用户重复点赞,可以在点赞表中以用户ID+文章ID为唯一索引,这样就可以有效的防止用户给一篇文章重复点赞,最终达到幂等操作的效果。
-
版本锁控制
版本锁属于是乐观锁的一种实现,MySQL中的MVCC就是版本锁的一种应用方式,通过每次更新都通过版本号控制权限来达到幂等操作的效果
-
token缓存机制
token缓存机制是一种比较常见的幂等处理方式,应用范围较广,不限定场景和语言。核心思想就是为每个请求分配一个全局唯一标识(token),一个token在一条业务线的每个阶段只能执行一次,执行之后将这个阶段的结果缓存起来,每次执行前先校验是否已有缓存,没有缓存则执行流程,已有缓存则直接返回结果。
总结
不同的业务需求会面临不同的幂等要求,也就会有不同的解决方案,所以幂等的实现难度是不同的。在做系统设计时,一定要将幂等性考虑周全,否则可能会给系统带来不必要的潜在隐患。