“幂等性”解析
定义:
一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。即,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
- 一次或多次请求对资源均没有副作用,比如查询数据库操作,没有增删改,因此对数据库没有任何影响
- 幂等性关注的是以后的多次请求是否对资源产生的副作用,而不关注结果
- 网络超时等问题,不在讨论范围
业务场景:
- 付款请求中,无论出现何种情况比如说网络问题,只应该扣一次钱。
- 验证短信
- 用户如果连续点击了多次提交订单,后台应该只产生一个订单
- …
实现方案:
-
唯一索引
操作的表有唯一索引时,新增重复记录就会报错 -
Token + Redis
页面数据提交前先申请有有效时间的Token,然后把Token存入Redis(Redis是单线程,处理任务时需要排队),当数据提交到后台时需要校验Token并删除该Token。 -
悲观锁
如在获取数据时加锁:select * from 表 where id = ‘1’ for update,当id字段不是主键或者唯一索引时,会引起锁表。一般情况下,悲观锁是同事务一起使用,故数据锁定时间会比较长,不推荐使用。 -
乐观锁
相较悲观锁而言乐观锁只会在更新数据时锁表,故效率较高,一般情况下使用version实现乐观锁。 -
分布式锁
比如Redis。订单发起支付请求,支付系统会去Redis缓存中查询是否存在该订单号的Key,如果不存在,则向Redis增加Key为订单号。查询订单支付已经支付,如果没有则进行支付,支付完成后删除该订单号的Key。通过Redis做到了分布式锁,只有这次订单订单支付请求完成,下次请求才能进来。 -
状态查询
操作数据之前,先查询一下关键数据,判断是否已经执行过,然后再进行相关业务处理。高并发业务不推荐使用,效率较慢。
类似的概念“防重复提交”
重复提交是在第一次请求已经成功的情况下,人为的进行多次操作,导致不满足幂等要求的服务多次改变状态。而幂等更多使用的情况是第一次请求不知道结果(比如超时)或者失败的异常情况下,发起多次请求,目的是多次确认第一次请求成功,却不会因多次请求而出现多次的状态变化。
实现幂等的缺点:
- 增加了实现幂等的代码方案,是整体业务变得更加复杂
- 实现幂等时,并行的功能改为串行执行,较低了效率