在HelloWorld中绑定邮箱非常简单:登录后进入“设置/我的账户”,找到“邮箱绑定”或“账户与安全”,输入常用邮箱,系统会发验证码到该邮箱,填写验证码并确认,绑定即完成,可用于找回密码和接收通知。
为什么要绑定邮箱?先弄清目的再动手 把邮...
阅读更多 →

想象你向收银台付款,结果网络卡顿,你又点了一次“支付”。理想情况是:无论你按多少次,最终只扣一次钱,结果一致。幂等性(idempotency)就是让重复请求在语义上等同于一次请求,避免副作用被执行多次。
幂等性:对于同一操作,执行一次与执行多次在结果上等价(副作用只发生一次或以可控方式)。
得到一点直觉:幂等不是某一层的事,可以在客户端、API网关、应用层、数据库层或消息层配合实现。下面分几种常见做法讲清楚优缺点。
思路:客户端生成唯一 key(比如 UUID),每次请求携带,服务端按 key 去重并返回已保存的结果。
思路:把“能唯一标识一次业务”的字段建成唯一索引(比如订单号 client_order_id)。如果重复提交会被数据库拒绝,从而只有一次生效。
思路:服务端发放一次性 token,消费后标记为已用,任何重复用该 token 的请求被拒绝或返回同一结果。
把业务拆成幂等的状态转换:接收->处理中->完成。重复到达同一状态只会返回当前状态而不重复执行后续副作用。
在消息处理端记录已处理的消息 id(比如 Kafka 的 offset 或业务 id),遇到重复消息直接丢弃或返回先前结果。
| 方法 | 优点 | 缺点 |
| 幂等键 | 灵活、客户端可控 | 需存储和失效管理 |
| 唯一约束 | 借助DB原子性,简单可靠 | 需要合适唯一字段 |
| 状态机 | 适合复杂业务,多步可回溯 | 设计复杂、实现成本高 |
| 消息去重 | 适合异步系统 | 需持久化已处理 id |
场景:一个简单的“说Hello”服务,客户端发送POST /sayHello,携带 name 与 idempotency_key。要求:同一幂等键返回相同响应,不重复写入数据库。
| 表:hello_requests | |
| id | 主键,自增 |
| idempotency_key | 唯一索引 |
| request_body | JSON |
| response_body | JSON |
| status | pending/finished/failed |
| created_at | 时间戳 |
1. 接口收到请求:读取 idempotency_key 和 body
2. 开始 DB 事务
3. 查询 hello_requests where idempotency_key = key
- 如果存在:
- 如果 status = finished:返回 response_body(HTTP 200)
- 如果 status = pending:返回 202 或等待/告知处理中
- 如果 status = failed:可以重试或覆盖(按策略)
- 如果不存在:
- 插入一条 status = pending 的记录(注意唯一约束避免竞态)
- 提交事务
- 执行业务逻辑(生成 "Hello, name")
- 更新记录为 finished 并写入 response_body
- 返回 response_body
这里的关键点是:插入时依赖数据库的唯一约束防止并发重复插入。遇到插入冲突时,另一条请求可以读取已有记录并根据其 status 决定返回或等待。
如果是简单服务,我会优先采用幂等键+数据库唯一约束:客户端生成 UUID,服务端插入 pending 记录并异步处理。对高并发或延迟敏感的场景,额外用 Redis 做短期去重与速率限制。对金融级别操作再加上事务日志与人工对账流程。嗯,这样既安全又工程化,出问题也好查。
碰到具体实现问题可以把你的技术栈、并发量和业务场景告诉我,咱们把示例代码调成可运行的样子。
了解更多相关内容
为什么要绑定邮箱?先弄清目的再动手 把邮...
阅读更多 →