一、产生幂等性问题的简单场景
假设场景:正在开发领取红包的功能,每人只能领取一次红包,点击按钮之后,服务端处理发红包请求,返回结果后按钮置灰,用户之后不能再领取红包。
正常流程如下
graph LR
请求发红包接口 --> 校验状态
校验状态 -- 未领取 --> 改变状态为已领取 --> 后续账户加钱服务
校验状态 -- 已领取 --> 拒绝请求
如果有人绕过前端直接请求接口,同时发出多个请求,由于状态校验和更改用户状态存在时间差,会有多个请求同时走到第一个分支,这样就会出现用户多次领取红包的情况,于是出现了幂等性问题。
二、什么是幂等性
这个概念来自于数学 ,在计算机领域可以理解为:一次请求和多次请求同一个资源产生相同的副作用。
用这个概念来看一般情况下(不考虑复杂SQL逻辑,唯一索引等情况),常见数据库的 增删改查 操作的幂等性
指定参数查询:幂等。查询参数不变,则结果不变
按Id删除记录:幂等。多次删除同一记录和单次删除同一记录结果相同
增加一条记录:非幂等。多次请求会多次增加记录
修改一条记录:需要讨论。SET a=1 为幂等,SET a=a+1 为不幂等
三、为什么需要幂等性
避免出现各种意料之外的情况: 发放超量用户奖励、扣减库存超额、数据库记录与实际业务对不上等等。
四、何时处理接口幂等性
- 设计请求时,用户同样参数的请求本应只有一次影响
有些业务场景下,用户请求了两次,造成了两次影响,但这两次完全可以看作独立请求,比如点击一次攻击一次怪物,两次点击就不能算作一次攻击
- 多次请求会造成非预期的结果
比如查询 get 请求,影响不大的情况下一般不做幂等处理
五、如何处理幂等性问题
前端的交互细节是第一道保障,后端是最后兜底的最重要保障。
前端常见幂等性实现: 按钮置灰、页面重定向;
后端常见幂等性实现: 业务逻辑层加锁、JUC提供的并发控制、数据库唯一索引去重、业务表加状态字段、单次请求周期唯一Id等等。
这里不细讲是因为离开业务谈幂等处理意义不大,前期要深刻理解剖析业务逻辑,一定要根据自己的业务特点去找合适的幂等方案,而不是刻意去八股文里找方案。