ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot防重复提交-加一把Redis锁就够吗

SpringBoot防重复提交-加一把Redis锁就够吗 Spring Boot 防重复提交锁、请求指纹与业务幂等的三层闭环问题现场Redis 锁只能约束同一时刻的并发无法阻止锁释放后的重试也无法证明第一次业务是否已经成功。用户连点、HTTP 超时重试、第三方回调重放和消息重复消费都表现为“请求来了两次”但需要的去重期限和结果语义完全不同。本文不再重复文章 052 已讲过的 Lua 解锁、TTL 与续期而是讨论请求指纹、入口短锁和业务幂等怎样形成闭环。一、先区分四种重复来源时间窗口推荐标识第二次请求的处理页面连点毫秒到数秒用户接口资源快速拒绝HTTP 重试秒到分钟客户端幂等号返回第一次结果第三方回调小时到天外部流水号只允许一次状态迁移消息重投取决于保留期messageId业务主键安全重放不先定义来源所谓防重最后往往只是给 URL 加五秒锁它能挡住双击却挡不住十秒后的网络重试。二、第一层是稳定请求指纹业务动作 租户或用户范围 资源标识 客户端幂等号没有幂等号时可以对规范化后的关键参数计算摘要但不能直接对原始 JSON 求哈希。字段顺序、时间戳、TraceId 和非业务字段都会造成同一业务生成不同 key。订单号、支付流水号等业务标识通常更稳定也更便于排查。三、第二层短锁只收敛并发窗口短锁只能保证同一指纹在有效期内由一个执行者进入。它不能回答锁释放后能否重试、响应丢失后返回什么以及业务耗时超过 TTL 后如何避免第二次写入。锁 key、TTL 和续期是并发控制参数不是业务幂等协议锁所有者校验和原子释放统一由文章 052 说明这里不再重复。四、MetaLite 当前解决入口互斥ApiRepeatSubmitHandler 位于 API_RECEIVE 入口处理链。它读取 RedisLock通过 SpEL 从已解析的方法参数生成 key成功获取锁后才允许业务继续执行。统一处理链保证解密和参数接收完成后再计算 key也避免业务方法散落加锁与解锁代码。后置阶段使用 AspectInfo 保存的 key 和唯一值释放锁。源码注册链也明确表达了“可选 Redis”的边界BeanpublicApiRepeatSubmitHandlerapiRepeatSubmitHandler(Autowired(requiredfalse)RedisLockerredisLocker){returnnewApiRepeatSubmitHandler(redisLocker);}处理器的关键分支可以压缩为if(redisLockernull){returnResp.ok();}RedisLocklock(RedisLock)aspectInfo.findMethodAnnotation(RedisLock.class);if(locknull){returnResp.ok();}returnredisLocker.lock(aspectInfo)?Resp.ok():Resp.error(接口正在处理中请勿重复提交);这条源码链至少包含ApplicationAutoConfiguration、ApiRepeatSubmitHandler、AspectInfo、RedisLock、RedisLocker和Resp六个可以核验的对象。它证明当前设计选择是Redis 或注解缺失时放行抢锁失败时阻断方法结束后由postHandle解锁。这个降级边界必须进入部署检查否则开发环境关闭 Redis 时很容易误判防重已经生效。RedisLocker 是可选能力所以代码存在注解不等于生产环境一定启用了防重。MetaLite 当前提供的是入口防线不能替业务完成长期幂等。五、第三层必须记录业务结果真正的幂等是“请求到达多少次最终只产生一次业务效果”。通常需要业务表唯一索引幂等请求表记录处理中、成功、失败和结果未知状态机限制非法重复迁移保存第一次成功响应供重试复用消费端记录消息与业务处理结果。支付回调可以用第三方流水号建立唯一约束。第二次插入冲突时应读取第一次结果并返回约定响应而不是把数据库异常直接暴露给上游。六、失败不一定意味着可以立即重试失败可能表示什么都没做、下游成功但本地失败或者结果未知。短锁释放只说明线程退出临界区不代表业务回到执行前。对于后两种状态重试可能再次扣款、发券或创建外部订单。幂等记录必须区分状态并提供查询、超时接管或补偿机制。七、用时间线验证闭环00s A 获得五秒短锁并调用下游 05s 锁过期 06s B 使用相同幂等号再次进入 08s A 写入成功 09s B 尝试写入同一业务结果完整闭环应保证指纹识别 A、B 是同一请求短锁尽量避免并发唯一约束或状态机保证只写入一次B 最终复用 A 的结果。集成测试应主动让业务耗时超过锁 TTL。只有这种测试才能证明系统防住的是业务重复而不只是正常速度下的双击。八、上线前检查key 是否包含稳定业务标识去重期限是五秒、一天还是永久第一次响应丢失时能否返回原结果锁过期后是否还有唯一约束或状态机是否区分失败、处理中和结果未知Redis 未启用时是放行还是拒绝是否测试过业务耗时超过 TTL把这些问题回答清楚防重复提交才从一个 Redis 注解升级为可验证的业务幂等协议。框架简介MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。源码基线JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3具体组件版本以项目backend-bom为准。作者简介15 年 Spring 体系企业级开发经验专注于 Java 微服务架构、工程治理与生产实践。持续更新MetaLite 系列内容将持续更新围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者及时获取后续内容。在线演示演示地址: https://admin.metalite.top/演示账号: guess演示密码: admin2026
返回列表