标准答案

  1. 先定义真正的去重维度,例如外部支付流水号、租户加客户端请求键、消息主题加业务事件 ID。
  2. 数据库 UNIQUE 约束是并发下最可靠的最终裁判,不能只先查再插入,因为两个请求可能同时通过查询。
  3. 去重记录应保存请求摘要、处理状态、结果引用和过期策略,以区分相同请求重试与同一个 Key 携带不同参数的异常。
  4. 幂等命中后应返回已完成结果或明确处理中状态,不能再次触发扣款、发货或消息投递。
  5. 失败后是否允许重试要由状态机决定,避免永久占用 Key 或把未知结果误判为可重新执行。

题目解析

“先 SELECT 再 INSERT”在并发下不是去重方案。只有把唯一事实写进同一原子竞争点,例如唯一索引或条件插入,才能保证两个请求中只有一个成为首次处理者。

幂等不仅是拒绝重复,还需要结果语义。客户端超时后重试时,如果服务端第一次已成功,应能返回同一订单或同一处理状态,而不是只回复“重复请求”。

代码示例

幂等记录通过唯一键竞争首次处理权,冲突后读取已有状态而不是再次执行副作用。

sql
CREATE TABLE idempotency_records (
  tenant_id BIGINT NOT NULL,
  idempotency_key VARCHAR(128) NOT NULL,
  request_hash CHAR(64) NOT NULL,
  status VARCHAR(32) NOT NULL,
  result_id BIGINT NULL,
  PRIMARY KEY (tenant_id, idempotency_key)
);

常见误区

  • 只用内存锁防重,进程重启、多实例或超时重试后重复执行。
  • 同一个幂等键传不同请求体仍返回旧结果,没有检测请求摘要冲突。

作者信息