-- 编号让位(2026-09-17):本文件原为 V149,与远端已推送的 V149__clear_service_hero_placeholders 撞号,本地让号改为 V152。 -- 支付尝试按「这一次尝试」收敛所需要的两列(判定见 docs/adr/0003)。 -- -- last_reconciled_at 对账任务的公平轮转与退避依据。旧实现按「最早 100 条」取未决流水,一旦积压 -- 超过上限,最新出现的那笔(也就是用户刚卡住的那笔)永远轮不到——而死锁唯一 -- 的自愈通道就是对账。改为「空值优先、升序、带退避」之后每笔都会轮到。 -- close_attempts 关单重试计数。关单回执说「处理中」时支付尝试落在 CLOSING,后台每分钟重试 -- 一次;到上限就不再重试(保留 CANCEL_UNCONFIRMED 盯防与问题记录),避免一条 -- 坏数据让后台永远重试同一笔。 -- -- 这两列必须同样落到开发库:开发库(局域网共享的 talent_card)Flyway 是关闭的、结构不由迁移维护, -- 所以另有 scripts/dev-schema-v149-payment-attempt.sql(可手工执行的等价 DDL)与 -- scripts/apply-dev-schema.ps1(本机没有 mysql 客户端,用项目已有的 JDBC 驱动执行)。 -- -- 用存储过程按 exists 判断逐列追加,使脚本可以重复执行(本地开发的库常常手工加过列)。 DROP PROCEDURE IF EXISTS add_payment_attempt_convergence_columns; DELIMITER // CREATE PROCEDURE add_payment_attempt_convergence_columns() BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'payment_transaction' AND column_name = 'last_reconciled_at') THEN ALTER TABLE payment_transaction ADD COLUMN last_reconciled_at DATETIME DEFAULT NULL COMMENT '最近一次对账处理时间(公平轮转与退避依据)'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'payment_transaction' AND column_name = 'close_attempts') THEN ALTER TABLE payment_transaction ADD COLUMN close_attempts INT NOT NULL DEFAULT 0 COMMENT '已发出的关单请求次数(重试上限依据)'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'payment_transaction' AND index_name = 'idx_payment_transaction_reconcile') THEN CREATE INDEX idx_payment_transaction_reconcile ON payment_transaction (status, last_reconciled_at); END IF; END // DELIMITER ; CALL add_payment_attempt_convergence_columns(); DROP PROCEDURE add_payment_attempt_convergence_columns;