软件开发过程中,系统的幂等性有哪些实现方案?

低调的牛肉


幂等性的概念

用户同一操作请求了一次或者多次,最终的结果应该是一致的,并不会因为多次请求产生副作用;幂等操作的特点是“多次执行所产生的结果与一次执行的结果相同”。比如:

  • 付款操作的时候,请求已经发送给服务端,但是由于网络原因未收到付款结果(实际上已成功),再次操作付款的时候,不应该成功;

  • 在页面做新建操作的时候,手抖连点了新增按钮,那么应该只会创建出一条数据;

查询和删除

查询和删除操作,天然具有幂等性;也就是多次执行查询或删除操作的时候,结果和执行一次查询或删除的结果是一样的。

但是要注意,多次执行删除的返回内容可能不同,比如第一次删除成功,后面再执行删除的话,会显示数据不存在。

保证幂等性的方案

新增和修改,如果不做幂等性处理,可能就会产生问题(如果修改只是把某些字段更新成固定的值,不会有幂等性问题,但是如果新值要在旧值上做处理做计算,如增加多少、减少多少,那么多次执行的结果就会有差异);那么保证幂等性有哪些方案呢?(给出我知道的方案,方案有好有坏)

  • 悲观锁:获取数据的时候加锁获取;select * from table where col='xxx' for update; 只能说是一种实现方案,但是不是特别好;

  • 乐观锁:在更新数据那一刻锁表,可以通过条件限制,也可以通过版本号来实现,比如:数据中增加版本号的概念,那么在做数据修改,把当前数据的版本号带上,修改的时候要按照版本号判断数据是否发生过更改。如果没有发生过更改,则执行业务操作,并更新版本号。

  • 分布式锁:在业务系统执行插入或更新操作的时候,先要获取分布式锁,然后做操作,之后释放锁;分布式锁保证在一个时间内,只会有一个线程对数据进行操作;


  • 全局唯一请求ID:每一次的请求,都带有一个全局唯一的请求ID,这个请求ID只要执行过一次就失效了:

  • 状态幂等:如果业务流程中的每个阶段,数据都有不同的状态,那么当数据已经处于下一个状态的时候,这时候又来了上一个状态的变更,是不会执行成功的(其实有些类似于版本号的概念,不过这个状态是有业务含义的)。

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。


会点代码的大叔


1 幂等含义

操作一次和操作多次结果一致被称为幂等。下面我们来分析几种常用幂等方案。


2 幂等表方案

场景:用户支付成功(订单ID=aaa)此时支付系统将支付成功的消息,发送至消息队列。物流系统订阅到这个消息,准备为这笔订单创建物流单。

但是消息队列有可能会重复推送,也就是说物流系统有可能接收到多次这条消息。我们希望达到的效果是:无论接收到多少条重复消息,只能创建一笔物流单。

方案:新建一张幂等表,该表就是用来做幂等的,无其它业务意义。该表有一个字段名为key,建有唯一索引,这个字段是幂等的标准。

当物流系统订阅到消息后,在创建物流单前,首先要将订单ID(本例=aaa)尝试插入幂等表的key字段。如果插入成功则继续做业务。不成功表示已经处理过了,丢弃消息。

这张表所有业务都可以操作,数据量会很大,需要定期清理,并将数据备份。

当然可以利用分布式锁锁住订单ID,判断是否已经有物流订单了,没有就创建物流订单。这种方法本质上是在解决并发问题。


3 状态机方案

场景:物流单处理成功,发送消息给订单系统,让订单更新状态为完成,假设操作是将订单status=0更新至status=1。同理订单系统也可能收到多条消息。

方案:使用状态机方案:status=0只能流转至status=1转态,并且status=1已经是最终态。当订单为status=1时,即使接收到物流单成功的消息也不在处理,丢弃消息。


4 乐观锁方案

(1) 先查出数据,数据中包含字段version

(2) 发送业务操作更新语句:update xxx set xxx,version = #{version} + 1 where id = #{id} and version = #{version}

(3) 如果此时该记录已经被修改,version就已经发生了变化,不能被更新成功


敬请关注

请点击关注按钮【IT徐胖子】会持续为大家奉献互联网和技术干货内容,感谢支持


IT徐胖子


1.对每次请求生成请求id,进行防重复,redis或者应用内缓存防重

2.很多请求本身就是幂等的,比如update指定的where条件,加版本乐观锁


分享到:


相關文章: