幂等性如何保证

什么是幂等性#

● 幂等性定义:
● 一次和多次请求某一个资源对于资源本身应该具有同样的结果
● 任意多次执行对资源本身所产生的影响均与一次执行的影响相同
● 幂等不仅仅只是一次或者多次请求对资源没有副作用
○ 比如,查询数据库操作,没有增删改,无论多少次操作对数据库都没有任何影响
● 幂等还包括第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用
● 幂等关注的是以后多次请求是否对资源产生副作用,并不关注结果
● 网络超时等问题,不是幂等的讨论范围
● 幂等性是系统服务对外一种承诺,而不是实现
● 承诺只要调用接口成功,外部多次调用对系统的影响是一致的
● 声明为幂等的服务会认为外部调用失败是常态,并且失败后必然会有重试

我们看下标准的restful请求,幂等情况是怎么样的:

  1. SELECT查询操作
    a. GET:只是获取资源,对资源本身没有任何副作用,天然的幂等性。
    b. HEAD:本质上和GET一样,获取头信息,主要是探活的作用,具有幂等性。
    c. OPTIONS:获取当前URL所支持的方法,因此也是具有幂等性的。
  2. DELETE删除操作
    a. 删除的操作,如果从删除的一次和删除多次的角度看,数据并不会变化,这个角度看它是幂等的
    b. 但是如果,从另外一个角度,删除数据一般是返回受影响的行数,删除一次和多次删除返回的受影响行数是不一样的,所以从这个角度它需要保证幂等。(折中而言DELETE操作通常也会被纳入保证接口幂等的要求)
  3. ADD/EDIT操作
    a. PUT:用于更新资源,有副作用,但是它应该满足幂等性,比如根据id更新数据,调用多次和N次的作用是相同的(根据业务需求而变)。
    b. POST:用于添加资源,多次提交很可能产生副作用,比如订单提交,多次提交很可能产生多笔订单。

常见解决方案#

方案1: 数据库唯一索引实现幂等 (防重表)#

在保存数据前,可以先select一下数据是否存在。如果数据已存在,则不再写入数据,如果数据不存在,则执行insert操作。
但在高并发的场景下,可能会出现两个请求select的时候,都没有查到数据,然后都执行了insert操作,所以此时会有重复数据产生,因此在数据库中,我们需要添加唯一索引来保证幂等。在数据库中,唯一索引是不会引起重复数据的兜底策略。

方案2: 数据库乐观锁实现幂等#

数据库乐观锁方案适用于执行更新操作,通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号等于数据库表当前版本号,则予以更新,否则认为是过期数据。
update account set amount=amount-50, version=version+1 where id=123 and version = 1;

方案3: 防重Token令牌实现幂等#

此方案包含两个请求阶段: 1.客户端请求服务端申请获取token。 2.客户端携带token再次请求,服务端校验token后进行操作。
类似数据库唯一索引,举个场景例子,进入订单创建页面时,请求唯一的token,然后创建时带上 token

方案4: 分布式锁#

分布式锁的逻辑是,每次请求都通过业务唯一ID来尝试获取锁,如果获取成功,就进行后续业务逻辑操作,如果获取失败,就舍弃请求直接返回。 分布式锁通常是基于redis来实现的。

方案5: 状态机#

很多时候,业务流程是有状态流转的,这个时候可以使用状态机来保证幂等性。 如订单业务中,存在状态「1-已下单,2-已支付,3-已完成,4-已取消」,按照业务流程,状态是依次流转的,所以在update操作时,我们就要根据本次的状态来更新下一次的状态。状态机其实是乐观锁的一种特例。

posted @   大阿张  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示
主题色彩