什么是接口幂等性? 就是代码执行一次和n次,产生的结果都是一样的。
防重复提交和接口幂等性的区别:
需要处理接口幂等性的情况?
1、select语句天生幂等
2、update语句,需要做幂等处理
3、delete语句,如果是精确删除,如id =1,不需要处理。如果是id>1,则需要
4、insert语句,如果是插入自增的id,比如增加数据,需要处理。如果是,手动填充id,传进实体,则不需要,因为数据库主键有唯一性约束,会报异常。
幂等性的做法:
1、token机制
- 客户端先发送一个请求去获取token,服务端生成一个token缓存到redis,然后返回给客户单
- 客户端发起业务请求,携带token。此时,会去缓存里查询是否有token,如果有,则执行业务,业务完成后,删除token。
- 客户端发起重复业务请求,会去查询缓存,没查到,执行失败。
注意:判断以及删除token,这两步需要保持原子性,否则会有并发的问题。可以用lua脚本实现。
全局唯一 ID 可以用百度的 uid-generator、美团的 Leaf 去生成
2、利用唯一性约束
1)利用sql主键或者唯一键的唯一性
执行业务的时候,会去数据库的去重表里面插入一条数据,如果插入成功,则执行成功,如果插入失败,则执行失败。
例如: 下单操作,禁止重复下单
解决方案:可以在mysql中定义requestId字段或用生成的orderID作为唯一性约束,然后插入数据。
如果数据已经插入过,会报mysql异常,在捕捉异常的时候返回跟插入数据的一样的结果。又或者在插入前先根据唯一性约束字段去查,如果查到有数据,则返回跟第一次插入同样的结果。
2) 基于redis的唯一性
- 执行业务请求的时候,先去试着插入数据到redis,用setnx命令,如果插入成功,执行业务,插入失败,不执行。
3、状态机
例如,我们tb_activity活动表里面有status字段,那status字段有未发布、活动中、结束等状态,如果此时活动编号为112233这个活动编号的活动status为活动中,再次收到更新状态为活动中的状态的请求,则会执行失败,则返回第一次一样的结果。
例如: select status from tb_activity where activity_code = "112233";
得到status = "活动中";
然后业务代码执行更新语句 update tb_activity set status ="活动中" where activity_code="112233" and status="未发布";
由于此时编号为112233的活动status为活动中,所以会执行失败,因此,返回影响行数为0,所以我们可以根据返回结果判断而做幂等。