接口的幂等性

接口幂等是说,用相同的参数调用一次和调用多次,其返回的结果应该是一样的

有些接口可以天然的实现幂等性,比如查询接口,对于查询来说,你查询一次和两次,对于系统来说,没有任何影响,查出的结果也是一样

比如一个接口时用来保存数据的,那如果用户在页面上,连续两次点击提交(点击提交后,页面加遮罩层除外),那势必会发送2次请求,如果接口没有做幂等,数据库肯定被插入了2条相同数据

如何把接口做成幂等的,如果没有状态的改变和数据库相关的,都设置成单例基本上不用处理就幂等了,如果有状态改变或者数据库操作的话要做一些额外的处理,

首先在接口接收参数后要先判断是否已经做过处理,处理过了,直接将之前的结果返回,没有处理过再处理

幂等的好处是,在分布式中如果出现网络情况超时,或者突然宕机,方便消费者发起重试,而不会对已经处理的结果产生影响。

全局唯一ID

如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。

从工程的角度来说,使用全局ID做幂等可以作为一个业务的基础的微服务存在,在很多的微服务中都会用到这样的服务,在每个微服务中都完成这样的功能,会存在工作量重复。另外打造一个高可靠的幂等服务还需要考虑很多问题,比如一台机器虽然把全局ID先写入了存储,但是在写入之后挂了,这就需要引入全局ID的超时机制。

使用全局唯一ID是一个通用方案,可以支持插入、更新、删除业务操作。但是这个方案看起来很美但是实现起来比较麻烦,下面的方案适用于特定的场景,但是实现起来比较简单。

去重表

这种方法适用于在业务中有唯一标的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据和写入去去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。

插入或更新

这种方法插入并且有唯一索引的情况,比如我们要关联商品品类,其中商品的ID和品类的ID可以构成唯一索引,并且在数据表中也增加了唯一索引。这时就可以使用InsertOrUpdate操作。在mysql数据库中如下:


1
2
3
4

insert into goods_category (goods_id,category_id,create_time,update_time)
values(#{goodsId},#{categoryId},now(),now())
on DUPLICATE KEY UPDATE
update_time=now()

多版本控制

这种方法适合在更新的场景中,比如我们要更新商品的名字,这时我们就可以在更新的接口中增加一个版本号,来做幂等


1

boolean updateGoodsName(int id,String newName,intversion);

在实现时可以如下


1

update goods set name=#{newName},version=#{version} where id=#{id} and version<${version}

状态机控制

这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为0,付款成功为100。付款失败为99

在做状态机更新时,我们就这可以这样控制


1

update `order` set status=#{status} where id=#{id} and status<#{status}

以上就是保证接口幂等性的一些方法。

引自:https://blog.csdn.net/jks456/article/details/71453053

posted on 2018-05-30 14:44  王大拿  阅读(38)  评论(0)    收藏  举报

导航