一、什么是幂等性:
HTTP/1.1中对幂等性的定义是:一次和多次请求某一资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
就是用户对于同一接口发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用
即同一个接口,多次发起同一个请求,必须保证操作只能执行一次。
因此在许多业务场景中,需要保证客户端的重复提交和服务端的多次重试,而资源只会产生一份最终结果。幂等机制的核心,就是保证资源唯一性。
如:订单接口,不能创建多个订单
支付接口,重复支付同一笔订单只能扣一次钱
表单重复提交,只能成功一次(保存一条记录)
回调接口,如果出现多次回调,则要保证只处理一次,并返回处理成功
二、解决方案
1、唯一索引(防止新增脏数据)
唯一索引或唯一组合索引来防止新增数据存在脏数据
当表存在唯一索引,并发时新增报错,说明记录已经存在了,返回成功即可。
2、token机制+redis(防止页面重复提交)
针对重复点击或者网络超时重试,或者nginx重发等情况导致数据被重复提交
具体实现:
1)服务方提供一个生成全局唯一随机数token的接口,客户端在调用业务接口前先向服务方发送请求获取token,在客户端获取token的时候,将token存入redis中。
① 服务方提供获取token的接口,token可以是uuid
② 客户端在调用业务接口前先调用接口获取token
③ 服务方在客户端获取token时,生成token,并将token 作为 key,客户端用户信息作为value,保存在redis中,然后返回token
④ 客户端请求业务接口时,将获取的token放在header(最好放在header中)或者作为请求参数请求接口
⑤ 服务端收到请求后,从headers中拿到token,然后根据token到redis中查找该key是否存在
⑥ 如果存在,业务处理成功后,从redis中删除此token。如果不存在,说明重复调用,返回请勿重复操作即可
注意:从redis中查询token和删除token,要保证原子性,应使用redis分布式锁或者lua脚本。
2)同样提供一个生成全局唯一随机数token的接口,客户端请求业务接口时,将获取的token放在header或者作为请求参数请求接口。
第一次调用,业务处理成功后,将随机数作为key,操作结果作为value,存入redis,同时设置过期时长。第二次调用,查询redis,如果key存在,则证明是重复提交,直接返回错误。
3、悲观锁,获取数据的时候加锁获取
4、乐观锁
只能适用于更新操作,可通过version版本号实现。
为了防止重复更新,类似CAS,先比较再更新。更新时version版本号作为条件,来确定更新前没有被更新过。更新后版本号+1。
5、分布式锁,redis或者zookeeper分布式锁。
6、先查询,后插入
END.