- 实现账户管理改进设计文档中的所有核心功能 - 三科目余额管理 (个人余额、劳动报酬、冻结余额) - 交易状态机 (created → pending → bank_submitted → success/failed/timeout → reversed) - 三键幂等体系 (JZTxId/BankTxId/SourceKey) - 优先级扣款规则 (先个人后劳动) - 在途资金管理 (可用→在途→结转/回退) - 三账对账闭环 (总账 = 银行账 + 在途净额) - 补偿服务域 (超时检测、重试、死信队列) - 虚拟银行模拟器用于业务测试 - 完整的集成测试套件 (133 个测试全部通过) - Docker 容器化部署配置 - 前端 Vue3 + TypeScript 项目结构
138 lines
6.5 KiB
SQL
138 lines
6.5 KiB
SQL
-- 账户管理模型扩展 - 数据库迁移脚本
|
||
-- 创建时间: 2026-01-05
|
||
-- 说明: 扩展三科目余额模型,增强交易状态机
|
||
|
||
-- =====================================================
|
||
-- 1. 扩展账户余额表 - 三科目模型
|
||
-- =====================================================
|
||
|
||
-- 添加三科目余额字段
|
||
ALTER TABLE account_balance
|
||
ADD COLUMN personal_balance DECIMAL(20,2) DEFAULT 0 COMMENT '个人余额(可用)' AFTER account_type,
|
||
ADD COLUMN labor_balance DECIMAL(20,2) DEFAULT 0 COMMENT '劳动报酬(可用)' AFTER personal_balance;
|
||
|
||
-- 重命名 frozen_amount 为 frozen_balance(语义更清晰)
|
||
ALTER TABLE account_balance
|
||
CHANGE COLUMN frozen_amount frozen_balance DECIMAL(20,2) DEFAULT 0 COMMENT '冻结余额(不可用)';
|
||
|
||
-- 数据迁移:将现有 system_balance 分配到 personal_balance
|
||
-- 注意:这是保守迁移,将全部可用余额放入个人余额
|
||
UPDATE account_balance
|
||
SET personal_balance = system_balance - COALESCE(frozen_balance, 0),
|
||
labor_balance = 0
|
||
WHERE personal_balance = 0;
|
||
|
||
-- 添加不变量校验的注释
|
||
ALTER TABLE account_balance
|
||
COMMENT = '账户余额表 - 不变量: personal_balance + labor_balance + frozen_balance = bank_balance';
|
||
|
||
-- =====================================================
|
||
-- 2. 扩展系统交易表 - 增强状态机和幂等键
|
||
-- =====================================================
|
||
|
||
-- 添加来源幂等键(用于外部入账去重)
|
||
ALTER TABLE system_transaction
|
||
ADD COLUMN source_key VARCHAR(128) COMMENT '来源幂等键(SourceKey)' AFTER bank_ref_no,
|
||
ADD COLUMN submitted_at DATETIME COMMENT '提交银行时间' AFTER confirmed_at,
|
||
ADD COLUMN version INT DEFAULT 0 COMMENT '乐观锁版本' AFTER submitted_at;
|
||
|
||
-- 创建来源幂等键的唯一索引(MySQL 自动忽略 NULL 值的唯一约束)
|
||
CREATE UNIQUE INDEX idx_source_key ON system_transaction(source_key);
|
||
|
||
-- 修改状态枚举以支持新状态机
|
||
-- 注意:MySQL 的 ENUM 修改需要包含所有旧值和新值
|
||
ALTER TABLE system_transaction
|
||
MODIFY COLUMN status ENUM(
|
||
'created', -- 已创建(初始状态)
|
||
'pending', -- 待处理(已建立在途)
|
||
'bank_submitted', -- 已提交银行
|
||
'success', -- 成功
|
||
'failed', -- 失败
|
||
'timeout', -- 超时
|
||
'reversed', -- 已冲正
|
||
'processing', -- 兼容旧状态
|
||
'confirmed', -- 兼容旧状态
|
||
'mismatch' -- 对账不匹配
|
||
) DEFAULT 'created' COMMENT '交易状态';
|
||
|
||
-- 数据迁移:将旧状态映射到新状态
|
||
UPDATE system_transaction SET status = 'bank_submitted' WHERE status = 'processing';
|
||
UPDATE system_transaction SET status = 'success' WHERE status = 'confirmed';
|
||
|
||
-- 添加提交时间索引(用于超时检测)
|
||
CREATE INDEX idx_submitted_at ON system_transaction(submitted_at);
|
||
CREATE INDEX idx_status_submitted ON system_transaction(status, submitted_at);
|
||
|
||
-- =====================================================
|
||
-- 3. 创建在途交易明细表(可选,用于细粒度在途管理)
|
||
-- =====================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS transit_detail (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
account_id BIGINT NOT NULL COMMENT '账户ID',
|
||
txn_no VARCHAR(32) NOT NULL COMMENT '关联交易号',
|
||
amount DECIMAL(20,2) NOT NULL COMMENT '在途金额',
|
||
from_personal DECIMAL(20,2) DEFAULT 0 COMMENT '来自个人余额',
|
||
from_labor DECIMAL(20,2) DEFAULT 0 COMMENT '来自劳动报酬',
|
||
status ENUM('pending', 'settled', 'rolled_back') DEFAULT 'pending' COMMENT '状态',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
settled_at DATETIME COMMENT '结转/回退时间',
|
||
INDEX idx_account_id (account_id),
|
||
UNIQUE KEY uk_txn_no (txn_no),
|
||
INDEX idx_account_status (account_id, status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='在途交易明细表';
|
||
|
||
-- =====================================================
|
||
-- 4. 创建补偿任务表
|
||
-- =====================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS compensation_task (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
txn_no VARCHAR(32) NOT NULL COMMENT '关联交易号',
|
||
task_type ENUM('timeout_check', 'reconcile', 'reverse', 'retry') NOT NULL COMMENT '任务类型',
|
||
status ENUM('pending', 'processing', 'completed', 'failed', 'dead_letter') DEFAULT 'pending' COMMENT '任务状态',
|
||
retry_count INT DEFAULT 0 COMMENT '重试次数',
|
||
max_retries INT DEFAULT 3 COMMENT '最大重试次数',
|
||
next_retry_at DATETIME COMMENT '下次重试时间',
|
||
error_message TEXT COMMENT '错误信息',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
completed_at DATETIME COMMENT '完成时间',
|
||
INDEX idx_status (status),
|
||
INDEX idx_next_retry (status, next_retry_at),
|
||
INDEX idx_txn_no (txn_no)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='补偿任务表';
|
||
|
||
-- =====================================================
|
||
-- 5. 创建不变量校验日志表(审计用途)
|
||
-- =====================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS invariant_check_log (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
account_id BIGINT NOT NULL COMMENT '账户ID',
|
||
check_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '校验时间',
|
||
personal_balance DECIMAL(20,2) NOT NULL COMMENT '个人余额',
|
||
labor_balance DECIMAL(20,2) NOT NULL COMMENT '劳动报酬',
|
||
frozen_balance DECIMAL(20,2) NOT NULL COMMENT '冻结余额',
|
||
bank_balance DECIMAL(20,2) NOT NULL COMMENT '银行余额',
|
||
transit_amount DECIMAL(20,2) NOT NULL COMMENT '在途金额',
|
||
is_valid TINYINT(1) NOT NULL COMMENT '是否有效',
|
||
difference DECIMAL(20,2) COMMENT '差异金额',
|
||
trigger_source VARCHAR(100) COMMENT '触发来源',
|
||
INDEX idx_account_time (account_id, check_time),
|
||
INDEX idx_is_valid (is_valid)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='不变量校验日志表';
|
||
|
||
-- =====================================================
|
||
-- 6. 扩展对账表 - 支持三账对齐
|
||
-- =====================================================
|
||
|
||
-- 添加三账对账结果字段
|
||
ALTER TABLE reconciliation_batch
|
||
ADD COLUMN bank_total DECIMAL(20,2) COMMENT '银行账汇总' AFTER mismatch_count,
|
||
ADD COLUMN transit_net DECIMAL(20,2) COMMENT '在途净额' AFTER bank_total,
|
||
ADD COLUMN ledger_total DECIMAL(20,2) COMMENT '总账汇总' AFTER transit_net,
|
||
ADD COLUMN three_account_balanced TINYINT(1) DEFAULT NULL COMMENT '三账是否平衡' AFTER ledger_total;
|
||
|
||
|