方法预览:
- insert前先select
- 加悲观锁
- 加乐观锁
- 加唯一索引
- 建防重表
- 根据状态机
- 加分布式锁
- 获取token
为什么接口要保证幂等性?
- 可能存在表单重复提交
- 防止接口重试
- 消费重复消息
具体方案
- insert前判断数据是否存在,如果数据不存在则insert,否则update
- 加悲观锁 update user amount = amount-100 where id=123; ------> 先加悲观锁 select * from user id =123 for update
以上方案注意两点: - mysql 引擎必须是innodb,支持事务
- id 必须是主键或者索引,否则锁表
- 悲观锁可能会导致大量的请求阻塞,影响接口性能
幂等接口和防重接口的区别?
显然幂等接口的要求要高一些,保证防重的要求下,还要返回的接口一致
- 乐观锁:先查select id,version from user --> update xxx,version = version+1 where id = xxx and version =?
- 加唯一索引 捕获异常DuplicateKeyException,MySQLIntegrityConstraintViolationException
- 加防重表
- 获取token(基于nonce的方案): 提交表单的时候,申请token--》token 返回给前端,不保存redis---》前端带着token 请求---》判断token 在 redis 是否存在,如果存在说明,重复请求,若不存在,放入redis ,然后进行后续操作