您的位置:首页 > 其它

常见的解决方案(2)接口幂等性

2019-01-22 15:29 281 查看

接口幂等性问题产生的原因:

假如有个服务提供一个接口(服务部署在多个服务机器),接着有个接口是付款接口。用户在前端上操作的时候,一个订单不小心发起了两次支付请求,然后这两个请求分散在了这个服务部署的不同的机器上,结果一个订单扣款扣两次。

保证幂等性的核心:

1、对于每个请求必须有一个唯一的标识。

2、每次处理完请求之后,必须有一个记录标识这个请求处理过了。

3、每次接收请求需要进行判断之前是否处理过的逻辑处理。

常见解决方案:

1、业务表内唯一索引:

如果要对创建销售出库单的接口保证幂等性,也就是说人家网络超时,重复调用的时候,保证一个订单只能有一个对应的销售出库单。针对销售出库单的表的订单id,创建一个唯一索引,你如果接口被重试,同一个订单创建一个销售出库单的话,一定会违反唯一索引,那么此时会报错。

2、业务表内状态机:

修改订单状态,比如说将订单状态修改为待发货的时候,update order set status = “待发货” where status = “待付款” and id = 1,订单的状态其实就变为了“待发货”。假如说id = 1的订单接口重复调用,又要执行一次这个操作的话就不会生效。通常会去判断一下的,当前是否处于某个状态,然后才能流转到下一个状态。 (状态为待付款的才能流转到待发货)

3、基于版本号的更新:

id name age version

1 张三 20 1

如果要调用这个接口,更新他的这个年龄,先得查一下他的版本号是多少。调用人家的接口修改他的年龄,要changeAge(1, 21, 1)。

在接口里保证分布式接口的幂等性:

update user set age=21, version=version+1 where id=1 and version=1

4、基于mysql的去重表 / 基于redis的去重

比如说接口方法为changeAge(1, 21, 1),将所有的参数拼接成一个字符串,或者是从这些入参里选择一些参数,可以唯一标识这一次请求的一些参数id和version,id和version每次请求都不一样的,应该是可以唯一的标识这一次请求。拼接的字符串:1_21_1

如果基于mysql,单独搞一个表出来,就一个字段,建一个唯一索引,插入这个1_21_1到表里去。如果这个接口被重复调用的话,1_21_1,再次插入一个表的话,唯一索引会报一个冲突出来,这次插入就会失败。

如果接口调用量很大,并发很高,选择使用redis,拼接一个串出来,直接set设置到redis里去,如果下一次人家请求再过来了,此时会发现这个key已经存在了,那么这个时候就不能执行了,因为已经出现重复调用了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: