标准答案
- 为业务事实设计唯一键,例如外部支付流水、用户加活动、订单请求号,并让数据库唯一约束成为最后一道重复创建防线。
- 库存扣减、余额变更和状态迁移应使用条件更新、乐观版本号或事务锁定,确保只有满足当前状态的请求可以提交。
- 重复请求通过幂等键返回已有结果,避免同一用户动作在并发窗口内执行多次。
- 跨服务副作用需要保存状态和外部标识,并用消息去重、对账或补偿处理至少一次投递和不确定回调。
- 分布式锁只适合缩小竞争窗口;锁超时、进程崩溃、时钟问题和锁服务故障都要求底层仍然可正确拒绝重复写入。
题目解析
并发问题的根源是多个请求都在旧状态上判断“可以执行”。正确方案要把判断和更新合并为不可分割的持久化操作。
不同业务可接受的重复代价不同。展示类任务可容忍最终去重,扣款和权益发放需要更严格的同步约束和审计。
常见误区
- 先查询是否存在、再插入,却没有唯一约束或事务保护。
- 认为加了 Redis 锁就不需要处理锁失效和数据库竞争。
- 只处理同步重复提交,忽略消息重复、回调重放和人工补偿。