在微服务架构下,我们在完成一个订单流程时经常遇到下面的场景:

一个订单创建接口,第一次调用超时了,然后调用方重试了一次
在订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次
当这笔订单开始支付,在支付请求发出之后,在服务端发生了扣钱操作,接口响应超时了,调用方重试了一次
一个订单状态更新接口,调用方连续发送了两个消息,一个是已创建,一个是已付款。但是你先接收到已付款,然后又接收到了已创建
在支付完成订单之后,需要发送一条短信,当一台机器接收到短信发送的消息之后,处理较慢。消息中间件又把消息投递给另外一台机器处理

以上问题,就是在单体架构转成微服务架构之后,带来的问题。当然不是说单体架构下没有这些问题,在单体架构下同样要避免重复请求。但是出现的问题要比这少得多。

为了解决以上问题,就需要保证接口的幂等性,接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。有些接口可以天然的实现幂等性,比如查询接口,对于查询来说,你查询一次和两次,对于系统来说,没有任何影响,查出的结果也是一样。

除了查询功能具有天然的幂等性之外,增加、更新、删除都要保证幂等性。那么如何来保证幂等性呢?

全局唯一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,int version);

在实现时可以如下

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

状态机控制

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

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

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

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

什么是幂等,什么情况下需要幂等,如何实现幂等相关推荐

  1. 一个数字可以在不损失精度的情况下达到的JavaScript的最高整数值是多少?

    这是由语言定义的吗? 是否有定义的最大值? 在不同的浏览器中是否有所不同? #1楼 您要用于按位运算的任何值都必须在0x80000000(-2147483648或-2 ^ 31)和0x7fffffff ...

  2. java biginteger转int_如何在不使用java.math.BigInteger的情况下使用Java处理非常大的数字...

    我认为程序员应该已经实现了自己的bignum库,因此欢迎在这里. (当然,稍后您会发现BigInteger更好,并且可以使用它,但这是宝贵的学习经验.) (您可以在github上关注本课程的源代码.此 ...

  3. 计算极限的时候,什么情况下可以用等价无穷小替换

    不知道大家在学习泰勒公式的时候,对泰勒公式和无穷小等价替换有没有很迷的时候,额,我有,在求极限的题目中,有的时候是可以使用无穷小等价替换,但是有的时候一用就错,但是一直都没有太纠结什么原因,一直以为是 ...

  4. java中如何把时间封装成类,java-如何在不使用任何不推荐使用的类的情况下将日期从一种格式转换为另一种格式的日期对象?...

    java-如何在不使用任何不推荐使用的类的情况下将日期从一种格式转换为另一种格式的日期对象? 我想将date1格式的日期转换为date2格式的日期对象. SimpleDateFormat simple ...

  5. 进一步封装axios并调用其读取数据(吐槽~在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据)

    注意!!!(修改于2020年7月18日) 在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据 报错截图如下 报错内容: {&quo ...

  6. c# .netframwork 4.0 调用 2.0时报错 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。...

    "System.IO.FileLoadException"类型的未经处理的异常在 XXX.dll 中发生 其他信息: 混合模式程序集是针对"v2.0.50727" ...

  7. c#中什么情况下用(int)什么情况下用Convert.ToInt32

    1.c#中什么情况下用(int)什么情况下用Convert.ToInt32   ? 比如说有一个string型的3 ,要给它转换成int型的是用(int)3 ,还是用Convert.ToInt32(3 ...

  8. 关于何种情况下使用DataGrid、DataList或Repeater的一些讨论

    作者:Scott Mitchell [概述] WEB开发自从有了基于脚本的WEB编程技术(如ASP)以来,经历了一个漫长的过程.通过使用微软的ASP.Net技术,传统的ASP中大量的.单调乏味的.重复 ...

  9. nodemanager不能正常关闭_在什么情况下不能使用罗茨风机及如何正确关闭罗茨风机...

    锦工风机给大家介绍一下在什么情况下不能使用罗茨风机及如何正确关闭罗茨风机在什么情况下不能使用罗茨风机: 1.机器故障 这一点其实不用说,因为你知道,设备是存在故障确实不能使用,但会有人感觉有轻微的故障 ...

最新文章

  1. jnotify监控linux系统,jnotify linux使用记录
  2. 国产最大AI开源框架再升级:一口气发布9大新产品,顺便送出亿元GPU算力
  3. C语言 | 基于STM32的MPU6050模块程序(主程序)
  4. a commit git 参数是什么意思_深入理解Git - 一切皆commit
  5. 两个字符串的最长公共子序列长度_程序员编程算法,解决文本相似度问题的最长公共子序列算法!...
  6. epoll实现socket通信
  7. LOB字段存放在指定表空间 清理CLOB字段及压缩CLOB空间
  8. unix 网络编程总结 二
  9. 中专学历就该被拒之门外?做Java开发改变命运难吗?
  10. php-有时候你会疑惑的小问题
  11. 2020计算机大纲,计算机专业2020考试大纲.doc
  12. 声笔码和声笔数码单字效率分析
  13. 利用urllib读取JSON,然后将JSON解析为Python对象 —— python学习笔记
  14. microbit python下mp3_语音 — BBC micro:bit MicroPython中文版 0.0.1 文档
  15. amcharts的使用介绍
  16. vue文件下载进度条
  17. “互联网+工业”下的大数据应用场景分析
  18. mysql导入表空间太慢_Oracle 11g统计表空间使用率很慢
  19. 瑞芯微RK3568对比RK3399性能解析
  20. Mozilla Firefox os系统构架详解

热门文章

  1. C语言深度剖析——关键字sizeof、整型数据存储深入、数据类型取值范围深入
  2. windows家庭版添加windows沙盒功能
  3. java 查看堆内存_查看java内存情况的几个常用命令
  4. 我们爱分享----200多个js技巧代码
  5. 解决window7中浏览器无法上网问题
  6. 用 JAVA 实现微信第三方登录
  7. 计算机专业初学者推荐书籍
  8. 听说你刚中了NIPS?恭喜(研究德扑、老鼠胡须等AI的都入围了)
  9. 最新冰盾DDoS防火墙V9.1 新增防护功能更强大
  10. tcl-debug的下载与安装及NSG2的下载与使用