本节摘要:列表接口批量增删改、跨资源的一致性动作,是契约里"一次干多件事"的组合动作。本节讲清批量操作的统一语义(复合文档、批量端点、部分成功),并用一个"多状态更新"案例对比本地事务与分布式事务/补偿策略的取舍,最后给出批量接口的幂等性设计。
阅读完本节,你应当能够:
POST /users 建一个用户不难。但要"一次建一百个、或一个请求改掉十个订单状态"时就遇上新问题:每条可能部分成功、失败,事务边界跨越多个资源,客户端不知道"哪些成了哪些没成"。批量操作是契约里的组合动作——做对是省事,做错是数据混乱的温床。
批量的收益和代价要一起算:它省的是"网络往返次数"和"服务端的逐条开销",但一行巨大请求体同样会拖垮网关与超时。所以批量接口通常要约定上限(比如一次最多 100 条),超出则让客户端拆批,而不是狠心吃下无限大的数组。设计时把"单批上限 + 返回超限错误"定进契约,比在运行时报 413 让人摸不着头脑要稳得多。
推荐三种方案的组合拳:
{"items":[{"email":"a@x.com"},{"email":"b@x.com"}]}
POST /users/batch 或复用方法加批量参数。部分成功的关键在响应结构,既要整体状态码又要条级明细:
{ "summary": {"succeeded": 2, "failed": 1}, "results": [ {"index": 0, "status": "created", "id": 101}, {"index": 1, "status": "created", "id": 102}, {"index": 2, "status": "failed", "code": "EMAIL_TAKEN", "reason": "邮箱已存在"} ] }
客户端能据此逐条处理:把 index=2 的失败高亮给用户,其余照常。
部分成功还牵扯一个状态码上的选择。整体到底回什么?常用的两个口径并存:整体回 200 但用 summary 说明有失败,或者一律回 207 Multi-Status 让"成与败并存的批量"有专用的语义。无论你选哪一个,契约里要固定只用一个口径,否则客户端不知道"到底看成败在 summary 还是看整体状态码"。还有个常被忽略的点:results 的顺序必须与请求体里的 items 一一对应,客户端才能靠 index 把失败准确定位到原条目——顺序一旦被打乱,index 就成了废索引,逐条对齐也会全盘错位。
批量把"一致性"顶到了台前:十来条要么都成、要么都别成(原子),还是允许部分成(非原子)?这要看业务能不能容忍中间态,给出三种典型策略对照:
| 策略 | 一致性 | 代价 | 适用 |
|---|---|---|---|
| 本地事务 | 原子、强一致 | 仅限单库 | 单服务单库的批量写 |
| 两阶段提交 | 强一致、跨资源 | 锁与协调重、脆弱 | 强一致要求高的短期跨资源操作 |
| 补偿式事务 | 最终一致 | 流程长、要写补偿逻辑 | 跨服务、长流程的分布式场景 |
本地事务最省心:一个数据库里把多条插入放在同一事务里,任意一条失败则整体回滚。两阶段提交能在跨库时强一致,但准备/提交两步的协调开销和锁成本高、还容易挂死。补偿式事务适合跨多个微服务的长时间流程:先各干各的乐观推进,某步失败再反向执行"撤销"动作(如扣款失败则给订单回滚状态),接受"最终一致、中间可能短暂不一致"。
背景:电商批量改一批订单的状态(待支付 → 已支付)。
操作:批量端点收到 ["待支付", "待支付", "已支付"] 中的前两条要改为已支付。
两条路:
UPDATE ... WHERE id IN (...) AND status='待支付',事务一次提交,命中数即成功数——原子、一致、最省心。结果与解读:单库走本地事务,多服务走补偿式,判断依据就一条——"事务边界能不能停在单个数据库里"。别再为跨服务硬上两阶段提交去背锁与协调的重负,除非业务真的不能接受任何中间态。
批量承接了大量写,幂等更不能含糊:给批量请求带幂等键(复用 2.7 的思路),服务器对同一批多次提交只执行一次;复合文档里逐条给唯一索引,重复条目用键去重。否则一次网络重试,就把整批重复写进去。
这里有个被反复问到的坑:批量幂等键该绑在整批还是逐条?默认绑整批——一个键代表"这一次批处理",服务器只要记住"这张键处理过、结果快照在",重放直接回快照即可。只有当你需要"允许同一批里某几条被分开重试"时,才细化到逐条键,但那会让去重复杂度成倍上升。多数场景整批一个键就够,复合文档里再靠逐条唯一约束防止批内重复,两层各管各的,不必为了"灵活"把键拆得太碎。
⚠️ 常见坑:批量接口整体返回 500 却不带"哪几条成了"。部分成功被淹没,客户端无从补救。宁愿把"部分失败"明明白白报出来,让客户端逐条对齐。
💡 关键直觉:批量与事务的取舍,本质是在"原子性"和"可用性/复杂度"之间对赌。交易的原子性越强,协调成本越高;能停在单个事务边界的,就别为跨服务背重负。
六套加固件全部装齐,契约已足够成熟、耐事故。下一章我们把它拉到车间四——做成文档、序列化、测过、送上网关与 CORS 配置,真正落地交付。