文章目录
- 一、定义
- 二、业务场景
- 三、保证幂等性常用方法
- 方案1: insert前先select(基于mysql的分布式锁)
- 方案2:加悲观锁 select * from table where id = '1' for update(基于mysql的分布式锁)
- 方案3:加乐观锁 增加一列:version 或者timestamp(基于mysql的分布式锁)
- 方案4:建防重复表(基于mysql的分布式锁,项目开发中常用)
- 方案5:通过状态标识字段(与乐观锁性质差不多)
- 方案6:基于redis的分布式锁
- 四、小结
一、定义
接口幂等性是指用户对于同一操作发起的一次请求或者多次请求的结果都是一致的,不会因为多次点击而产生副作用。这类问题多发生于接口的:
1.insert操作
2 update操作,如果只是单纯的更新数据,例如:update user set login_num=1 where id = 1 是没有问题的,如果还有计算,比如:update user set login_num=login_num+1 where id = 1 ,这种情况下,多次请求,可能会导致数据错误。
简单来说:幂等性=多次相同请求,数据库无重复数据+多次相同请求,返回结果一样
二、业务场景
1.填写某些form表单时,保存按钮不小心快速点了2次,表中就产生了2条重复的数据,只是id不一样(解决方案:前端控制+方案1/方案6)
2.在项目接口中为了解决接口超时问题,通常会引入重试机制,第一次请求超时,被调用方没能返回结果,于是会对该请求重试几次,这样也会产生重复的数据(解决方案:方案4)
3.mq消费者在读取消息时,有时候会读取到重复的消息,处理不好,也会产生重复的数据(解决方案:方案4)
三、保证幂等性常用方法
方案1: insert前先select(基于mysql的分布式锁)
流程图如下:
方案1说明
性能不如redis分布式锁,查询条件必须走索引,否则会锁整张表
方案2:加悲观锁 select * from table where id = ‘1’ for update(基于mysql的分布式锁)
流程图如下:
方案2说明
性能不如redis分布式锁,查询条件必须走索引,否则会锁整张表,容易造成死锁
方案3:加乐观锁 增加一列:version 或者timestamp(基于mysql的分布式锁)
流程图如下:
方案3说明
SQL-1:update user set amount = amount-100,version=version+1 where id = 1 and version =1
性能不如redis分布式锁,增加了列,增加维护成本,性能高于悲观锁
方案4:建防重复表(基于mysql的分布式锁,项目开发中常用)
流程图如下:
方案4说明
性能不如redis分布式锁,加了表,增加维护成本,在项目开发中常用,推荐使用
方案5:通过状态标识字段(与乐观锁性质差不多)
流程图同乐观锁
方案5说明
比如 订单的状态有1-下单 2-已支付 3-完成 4-撤销等状态
SQL-1:update set status=3 where id = 1 and status = 2
方案6:基于redis的分布式锁
流程图如下:
方案6说明
性能最好,如果并发过高,key过期时间过短或过长,会导致redis的负担很重;小并发场景推荐使用,太高的并发需要redis集群,推荐使用
四、小结
完整的幂等性, 除了后端外,前端也需要做防重复点击设计。