如何保证接口幂等性?

一、什么是接口幂等性?

所谓的接口幂等性就是,针对同一个接口,多次发出同一个请求,必须保证操作只执行一次。

系统中一些核心的接口如果没有实现接口幂等性会有很严重的后果,比如:

  • 下单接口,同一个订单可能会创建多次,导致出现多张相同的订单
  • 支付接口,重复支付会导致多次扣款

幂等性问题多发生于新增操作和修改操作当中:

  • insert操作:这种情况下多次请求,可能会产生重复数据。
  • update操作:这里要分两种情况,一种是单纯的更新数据,比如:update order set status=0 where id = 1;,这种是没有问题的,无论执行成功多少次状态都是一致的,是幂等操作,但是如果你的更新sql里面还包含着计算逻辑,比如:update order set num = num+1 where id =1;,对于这种sql,如果多次执行,那就会导致数据错误了。

二、幂等性的解决方案

对于这个问题,我们有两个方向,一是在客户端浏览器做防止重复提交的处理,比如按钮置灰、加loading状态,但是这种方式不绝对可靠,比如别人可以直接通过类似postman这种工具来对后端发起请求,直接跳过你前端做的限制;另一个是在服务端做是否重复提交的校验。

接下来我们进行详细说明:

1.使用唯一索引来防止新增脏数据

利用数据库唯一索引机制,当数据重复时,插入数据库会抛出异常,保证不会出现脏数据。

2.乐观锁

这里的乐观锁指的是用乐观锁的原理去实现,在数据表中新增一个version字段,通过version字段来做乐观锁,当数据需要更新时,先去数据库里获取此时的version版本号,如:

sql 复制代码
select version from test where id = 1;

更新数据时首先跟查出来的版本号去做对比,如果不相等,说明在此之前已经有其他的请求去更新过数据了,提示更新失败。

sql 复制代码
update test set status=status+1,version=version+1 where id=1 and version=#{version}

更新的时候会同时将version字段进行加1。

3.加悲观锁

在获取数据时进行加锁,当同时有多个重复请求时其他请求无法进行操作。

下面进行举例说明,比如用户下订单,进行支付,用户的账号里面有200元,需要支付100元,正常情况下用户的账号支付完成后还会有100元。sql如下:

sql 复制代码
update account set amount =  amount - 100 where id = 1;

如果出现多次相同的请求,就会导致该用户的余额变成负数。此时我们可以使用悲观锁,将该用户的那行数据进行锁住,在同一时刻只允许一个请求获得锁,更新数据,其它请求需要等待。

通过如下sql锁住单行数据:

sql 复制代码
select * from account where id  = 1 for update;

下面我们画一下流程图,更直观一点:

注意:这里的id字段必须是主键或者唯一索引,不然会锁住整张表。(FOR UPDATE是否会锁表取决于查询条件是否使用了索引或主键:如果条件使用了索引或主键,则通常为行锁;否则可能升级为表锁。‌‌)

4.建立防重表

以支付功能为例: 使用唯一主键去做防重表的唯一索引,比如使用订单号作为防重表的唯一索引,每一次请求都根据订单号向防重表中插入一条数据,插入成功说明可以处理后面的业务,当处理完业务逻辑之后删除防重表中的订单号数据,后续如果有重复请求,则会因为防重表唯一索引原因导致插入失败,直接返回操作失败,可以看出防重表作用就是加锁的功能。

5.token机制

这种方案需要两次请求才能完成一次业务操作:

1.第一次请求是去获取token的。

2.第二次请求带着这个token去完成后续的业务操作。

举个例子来说明:

  • 在进入到提交订单页面之前,需要调用获取token的接口,然后将token保存到redis当中。
  • 支付的时候带上token,后端检查redis当中是否存在该token,如果存在,表示第一次发起支付请求,删除缓存中的token开始处理支付逻辑;如果缓存中不存在,说明之前已经支付过了,返回错误。
相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!5 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
俊昭喜喜里5 天前
java中的继承和多态的区别
java
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕5 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码5 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖5 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时5 天前
01-06-A-JVM排查实战详解
java·jvm