接口的幂等性是什么?直接百度就可以出来,百度百科中是这么解释幂等的,在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
那么在我们平时开发的时候这种接口幂等性遇到的多么?我经历的这几家公司差不多每次都会遇到这种因为多次操作导致接口不幂等的情况,每次也很无奈的去直接操作数据库,把多余的数据删除了。
前端时间,我所负责的一个业务就出现了接口频繁操作,导致数据重复的情况,而且持续了好长一段时间,测试大佬们也每天都在催着我解决这个问题。
等我看完代码的时候我发现,我在核心的代码里面加了分布式锁,但是为什么还是没有任何效果呢?
public static void main(String[] args) {
RedisComponent redisComponent = new RedisComponent();
System.out.println("非核心代码~~~~~~");
redisComponent.setIfAbsent("lock","1",5000L);
System.out.println("核心代码~~~");
redisComponent.del("lock");
System.out.println("非核心代码~~~~~~");
}
大体上就是这么个意思,核心代码里面有很多的查询数据库和插入数据库的操作,但是还是会经常出现核心代码里面在极短的时间内执行好几次的情况。
最开始呢,我以为是写库没有及时通道数据到读库上导致的,我还专门去找DBA去问了,在执行的这段时间里面,是不是有什么网络波动的情况,DBA大佬说并没有。
然后我就很苦恼,为什么我加了分布式锁,应该不会出现多次执行核心代码的情况的。
在我去看ELK日志的时候,我发现我执行的一秒钟内,竟然有7~9次执行的接口。
这让我很慌张的,如果这个分布式锁并没有拦住这么多情况的话,我是不是应该考虑换一个锁试一下呢?
抱着试探性的态度,我去找我们领导说了一下,目前的情况,并且询问了一下是不是有其他的分布式锁可以使用。在领导的指引下,才发现这个锁生效的期间可能就几十或者几百毫秒,这样就可能在一秒之内执行多次的核心代码。
原来我也会写出来这么大的bug呀
既然知道了问题所在,就知道怎么解决了
第一种方案,就是锁定时间内,不然这个分布式锁删除,让这段时间内的情况不能重复操作。当时这个方案并不是很理想。
第二种方案,就是在每一次核心代码插入数据库的时候,都提前做一些判断,看看数据是否已经重复了。这个方案很多,但是如果核心代码里面有很多很多的数据库插入的话,那么就需要想想我们需要加多少代码了。
第三种方案,也是最简单的方案把拦截的分布式锁,扩大,扩大到执行非核心代码里面也有,这样呢,就可以在每一次请求进行的都是都会直接加锁,等执行完了,在进来的时候就已经报错了。
当然,保证接口幂等性并不是只有一种办法,可以保证接口幂等性的方法有很多,主要看是否与我们的业务吻合。
如果有token,大家可以直接只用token和接口的名字进行校验。
如果线上环境支持for update操作,也可以直接在sql里面添加for update
如果只是对一个数据状态的调整,可以使用指定转台来执行 sql
方法有很多,我这里讲的这个只是我在实际工作的时候遇到的。