什么是接口幂等性
接口幂等性是指:某些接口在被调用任意次数后,此接口对数据的操作每次结果都是相同的,即第一次操作和第N次操作接口的结果都是相同的,就像数学中某些数字的任意次幂其结果也都是数字本身。
不会产生接口幂等性的操作
在Java中有些操作其本身就是天然幂等性的,例如查询操作、删除操作、以下两条语句无论执行任意次,其结果都是相同的。
部分更新操作,部分插入操作。
假设name字段或age字段有唯一性约束,此类的插入将是幂等性的操作
insert into user (name,age) values ('张三',33)
一个接口至少进行两次参数相同的操作,如果其结果都是相同的,那么则此接口就具有幂等性,否则反之。
那些情况下会发生接口幂等的问题
用户快速多次点击付款按钮,用户页面回退再次提交,由于网络问题,导致请求失败。触发重试机制自动提交的操作…
解决接口幂等的方案
Token机制利用Token令牌防止重复操作。在用户操作前向服务器获取一个具有唯一性的Token,在操作时携带此Token,由服务端验证此Token是否存在,不存在则抛弃本次请求,如果存在则在验证token之后操作接口之前删除Token。Token可以存储在Reids数据库提高性能。Token获取、比较和删除必须是原子性。redis.get(toke、tokeequals、redis.del(toke,如果操作不具有原子性,可能导致,高并发下,都get到同样的数据,判断都成功,继续业务并发执行。
使用锁机制
数据库悲观锁select*fromxxxxwhereid=1forupdate;悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,需要根据实际情况选用。另外要注意的是,id字段一定是主键或者唯一索引,不然可能造成锁表的结果,处理起来会非常麻烦。数据库乐观锁这种方法适合在更新的场景中,updatet_goodssetcount=count-1,version=version+1wheregood_id=2andversion=1根据version版本,也就是在操作库存前先获取当前商品的version版本号,然后操作的时候带上此version号。我们梳理下,我们第一次操作库存时,得到version为调用库存服务version变成了2;但返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订单服务传如的version还是再执行上面的SQL语句时,就不会执行;因为version已经变为2了,where条件就不成立。这样就保证了不管调用几次,只会真正的处理一次。乐观锁主要使用于处理读多写少的问题。
业务层分布式锁
如果多个机器可能在同一时间同时处理相同的数据,比如多台机器定时任务都拿到了相同数据处理,我们就可以加分布式锁,锁定此数据,处理完成后释放锁。获取到锁的必须先判断这个数据是否被处理过。
各种唯一约束
数据库唯一约束插入数据,应该按照唯一索引进行插入,比如订单号,相同的订单就不可能有两条记录插入。我们在数据库层面防止重复。这个机制是利用了数据库的主键唯一约束的特性,解决了在insert场景时幂等问题。但主键的要求不是自增的主键,这样就需要业务生成全局唯一的主键。如果是分库分表场景下,路由规则要保证相同请求下,落地在同一个数据库和同一表中,要不然数据库主键约束就不起效果了,因为是不同的数据库和表主键不相关。
Redisset防重
很多数据需要处理,只能被处理一次,比如我们可以计算数据的MD5将其放入Redis的set,每次处理数据,先看这个MD5是否已经存在,存在就不处理。
全局请求唯一id
调用接口时,生成一个唯一id,Redis将数据保存到集合中,存在即处理过。可以使用Nginx设置每一个请求的唯一id;proxy_set_headerX-Request-Id$request_id;
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点