From a76c7a80b98cec7c6f730364c321cf0c39f3fde2 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Thu, 6 Aug 2026 11:07:42 +0800 Subject: [PATCH] =?UTF-8?q?chore(changelog):=20=E7=94=A8=E8=BD=A6=E9=9C=80?= =?UTF-8?q?=E6=B1=82=E9=87=8D=E5=A4=8D=E6=8F=90=E4=BA=A4=E5=B9=82=E7=AD=89?= =?UTF-8?q?=EF=BC=88#5575=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ATE锁修复+同内容重放不产生新行)-修改接口-管理后台.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 changelogs-v2/2026-08/06_5575_用车需求重复提交幂等(FOR-UPDATE锁修复+同内容重放不产生新行)-修改接口-管理后台.md diff --git a/changelogs-v2/2026-08/06_5575_用车需求重复提交幂等(FOR-UPDATE锁修复+同内容重放不产生新行)-修改接口-管理后台.md b/changelogs-v2/2026-08/06_5575_用车需求重复提交幂等(FOR-UPDATE锁修复+同内容重放不产生新行)-修改接口-管理后台.md new file mode 100644 index 0000000..4e0f96c --- /dev/null +++ b/changelogs-v2/2026-08/06_5575_用车需求重复提交幂等(FOR-UPDATE锁修复+同内容重放不产生新行)-修改接口-管理后台.md @@ -0,0 +1,64 @@ +--- +schema: "hl-changelog/v2" +ticket: "5575" +title: "用车需求重复提交幂等(FOR UPDATE锁修复+同内容重放不产生新行)" +consumer: "admin" +author: "wx(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "后端完成:PR #5584/#5585 已合并 dev-v3 并部署 TEST;网关验证 3/3(连续同内容重放 2 次均返回 IDEMPOTENT_NOOP 同 requirementId,无新行;内容变化仍走 PENDING_EDIT);存量 v3 双行已按清理 manifest 清理。响应新增 branchTaken=IDEMPOTENT_NOOP 取值(前端可据此提示'内容未变化'),其余契约不变。" +updated_at: "2026-08-06" +base: "dev-v3" +generated: "2026-08-06T11:07:21+08:00" +--- + +# 用车需求重复提交幂等(FOR UPDATE锁修复+同内容重放不产生新行) + +> 后端完成:PR #5584/#5585 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。 + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#5575](https://git.1814.love:8443/wx/HL/issues/5575) +- **PR**: [#5584](https://git.1814.love:8443/wx/HL/pulls/5584)、[#5585](https://git.1814.love:8443/wx/HL/pulls/5585) +- **Merge commit**: [1839b2aa4](https://git.1814.love:8443/wx/HL/commit/1839b2aa4)、[dac3e9347](https://git.1814.love:8443/wx/HL/commit/dac3e9347) + +### 联系人 + +- **后端负责人**: @wx + +## 背景 + +订单 2080600006514872322 需求 V3 两条记录(2085009136168177665 PROCESSING + 2085009096510935041 PENDING,同 version=3)——重复提交双写(双击/重试/重放)。 + +## 修复 + +1. **并发双写**:`VehicleRequirementMapper.selectLatestByOrderIdForUpdate` 的 `.last("FOR UPDATE").last("LIMIT 1")`——MyBatis-Plus `last()` 覆盖式,LIMIT 1 覆盖掉 FOR UPDATE → 提交事务退化为快照读,并发提交基于同一快照算出同 version 双行。修复为单段 `.last("LIMIT 1 FOR UPDATE")`(MySQL 语法 FOR UPDATE 须在 LIMIT 后) +2. **顺序重复提交**:PENDING/PENDING_REVIEW 分支先做内容语义比较(fleet/行程日期/接送机/特殊标签/备注,JsonNode 解析比较兼容存量空格/字段序差异),完全一致时返回 `IDEMPOTENT_NOOP` 分支的当前版本——不插新行、不失活旧行、不触发 expand/reconcile/outbox + +## 变更接口 + +| 方法 | 路径 | 来源 | +|---|---|---| +| `PUT` | `/v3/admin/order/{id}/vehicle-requirement` | `VehicleRequirementAdminController`(order-v3) | + +**请求/响应字段无变化**。响应 `branchTaken` 新增取值 `IDEMPOTENT_NOOP`(重复提交时返回当前 requirementId/version 不变)。 + +## 前端/调用方动作 + +1. 提交按钮**可重复点击**:同内容重复提交返回 `branchTaken=IDEMPOTENT_NOOP`,前端可提示"内容未变化"或直接忽略,**无需**做前端防抖(后端已幂等) +2. 内容变化提交仍走 `PENDING_EDIT`/`DONE_ADJUST`,行为不变 + +## 验证证据 + +- 定向测试:RequirementServiceTest 198/198(+2:同内容→IDEMPOTENT_NOOP 且 insert/update/expand 未调用;内容变化→PENDING_EDIT);MapperTest 7/7(+2 SQL 形态断言);VehicleRequirementConcurrentVersionMysqlTest 4/4(+1 真实 MySQL LIMIT 1 FOR UPDATE 并发用例) +- 网关验证(TEST):HL20260805165915481 连续同内容重放 2 次均返回 IDEMPOTENT_NOOP 同 requirementId(2085199671193411585)v1,无新行;存量带空格 fleet JSON 语义比较正确 +- 数据清理:2080600006514872322 v3 双行按 manifest 清理(删 2085009096510935041,保留 2085009136168177665),v1-v5 各版本唯一 +- 兼容性结论:无契约变化;存量数据语义比较兼容;未传字段的旧调用保持原行为