21 | 双人审批与死锁实验卡 | 2026-10-04 已有源码:JdbcRequestStore.transition 使用 id + tenant_id + status + version 条件 UPDATE,更新 0 抛 RequestConflictException;purchase_order(request_id) UNIQUE。现有场景 scenarios/09-lab-procurement.sh 仅运行单租户流程,不是并发探针。 待做单行争抢 NOT_RUN:隔离库新建 SUBMITTED version=0 测试申请,保存 id;A 和 B 分别 BEGIN。A UPDATE 同 id 改 APPROVED、version=version+1,保持未提交;B UPDATE 同 id 改 REJECTED、version=version+1,等待;A COMMIT 后 B 预期 UPDATE 0;B ROLLBACK;第三连接预期 APPROVED/version=1。把 A/B 先后交换,再测。实际每次先核对 tenant_id 与 id,若更新行数异常说明准备无效。 待做死锁 NOT_RUN:隔离库两条 SUBMITTED 申请;A 先锁小 id,B 先锁大 id;A 异步尝试更新大 id,B 再更新小 id;一端预期 SQLSTATE 40P01,失败事务 ROLLBACK,另一端 COMMIT。按小 id 到大 id 的统一顺序重试完整事务对照;用有限超时,保存 pg_backend_pid、锁取得顺序、语句结果及最终状态。若未建立交错,报告未触发,不能宣称无死锁。 不要在真实审批订单上测锁,也不要把 55P03(锁超时)与 40P01(死锁)混作同一种结果。证据字段:测试数据 SQL、客户端/DB 版本、两个连接日志、SQLSTATE、最终行、重试次数与退出码。