知识全景图/ 软件工程与系统/ 如何设计业务数据库/ 业务状态机

如何设计数据库业务状态机

status 不是展示标签,而是控制哪些动作允许发生。

这页只讲一件事:已作废账目为什么不能继续进月报和余额。

一、先看事故
事故根因设计动作
已作废账目还进月报。只改主表状态,派生规则没跟上。状态迁移必须带副作用清单。
管理员把 posted 改回 draft。状态写路径散落。用迁移规则和前置条件收口。
银行 reversed,本地仍 posted。外部事实和本地主状态混在一起。主状态、外部状态、展示状态分开。
已对账账目被原地改金额。没区分活动态和锁定态。锁定态只能调整或冲正。
状态修复后搜索仍错。修状态没触发派生重算。状态事件驱动重算和复核。
判断:状态机设计的核心不是列枚举,而是定义合法迁移、禁止绕写、记录原因、同步派生结果。
二、建表前只问 5 个问题
问题最低设计
这是主业务状态,还是外部事实 / 展示状态 / 处理状态?不同含义不要混成一个 status
哪些状态能进入余额和月报?统一派生规则,不让每条 SQL 自己猜。
状态能从哪里迁到哪里?迁移规则和前置条件。
谁推动了状态变化,为什么?state_events 记录原因和操作者。
状态变化影响哪些派生结果?余额、月报、搜索、导出要有重算边界。
三、最小模型
ledger_entries: id, ledger_id, status, external_status version, status_updated_at state_events: id, entity_type, entity_id from_status, to_status, reason_code actor_type, actor_id, request_id, created_at state_transition_rules: entity_type, from_status, to_status required_condition, side_effect_policy
四、验收规则
样本通过标准
posted 直接回 draft。非法迁移被拦住。
voided 仍进月报。月报和余额对账失败并报警。
reconciled 原地改金额。禁止修改,要求调整分录。
外部回调重复到达。状态迁移幂等,不重复触发副作用。
两个 worker 同时推进。只有一个成功,另一个看到版本冲突。
五、下一步
并发推进状态
继续看幂等、版本冲突和失败重试。
生产状态已错
继续看 dry-run、合法迁移重放和复核。
记住:状态是控制面。没有迁移规则和状态事件,status 很快会变成谁都能改的危险字段。