10 KiB
10 KiB
RailwaySystem 数据库 V2 DDL Review Round 2 变更记录 (最终静态收尾)
修订阶段:数据库 V2 DDL Review Round 2(最终静态收尾)
最高依据:RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0.md
修订目标:解决高级技术负责人 Final Static Review 提出的 7 个核心静态问题(R2-01 ~ R2-07),使数据库 V2 DDL 达到“允许进入测试迁移”状态。
变更明细清单 (R2-01 ~ R2-07)
R2-01: 修正住宿状态默认值
- 问题:
train_accommodation.accommodation_status原默认值为1(已入住)。而正式业务流程为:名单确定 -> 报到前宿舍预分配 -> 学员报到核验 -> 展示已分配宿舍 -> 实际入住。若默认直接为已入住,与真实业务全生命周期相悖。 - 原实现:
accommodation_status SMALLINT NOT NULL DEFAULT 1 - 修改文件:
- 修改后实现:
字段注释保持为:
accommodation_status SMALLINT NOT NULL DEFAULT 0住宿状态 (0:预分配, 1:已入住, 2:已退宿);010_verify.sql中新增对accommodation_status默认值精确为 0 的强断言。 - 验证方式:静态文本检索与
010_verify.sql自动化断言规则核验。 - 是否解决:已彻底解决。
R2-02: 删除“业务选择型默认值”
- 问题:原 SQL 中对部分必须由调用方主动选择的业务输入字段设置了
DEFAULT 0或DEFAULT 1,特别是verify_result DEFAULT 1(核验通过),会导致应用层若漏传该参数,数据库自动判定通过,掩盖业务逻辑缺陷;同样,考勤方式、场地类型、住宿需求、来源类型等必须由业务明确提供,不允许数据库代替调用方猜测。 - 原实现:
train_enrollment.source_type:DEFAULT 1train_enrollment.accommodation_required:DEFAULT 0train_lesson.venue_type:DEFAULT 1train_student_score.source_type:DEFAULT 1train_student_checkin.checkin_way:DEFAULT 1train_class_report.verify_result:DEFAULT 1
- 修改文件:
- 修改后实现:
上述 6 个字段全部移除
DEFAULT声明,仅保留SMALLINT NOT NULL。010_verify.sql中增加只读断言:上述字段的column_default必须全部为NULL,若存在默认值当场抛异常。 - 验证方式:静态 grep 全局检索与
010_verify.sql断言校验。 - 是否解决:已彻底解决。
R2-03: 清除 Enrollment 来源的臆造枚举并解耦双 source_type
- 问题:
train_enrollment.source_type注释中原先硬编码了“1:组织指派, 2:自主报名, 3:单位推荐, 4:统一调训”,这属于未经正式会议冻结的臆造业务流程枚举;且容易与train_student.source_type(学员长期主档来源)发生混淆。 - 原实现:
COMMENT ON COLUMN train_enrollment.source_type IS '进入本期培训名单的来源 (1:组织指派, 2:自主报名, 3:单位推荐, 4:统一调训)'; - 修改文件:
- 修改后实现:
- 注释修改为:
COMMENT ON COLUMN train_enrollment.source_type IS '参训名单来源,具体字典值由 train_enrollment_source 定义'; - 文档中明确解耦定义:
train_student.source_type:学员长期主档进入系统的来源(管理员录入/Excel导入/平台同步);train_enrollment.source_type:人员进入“本期培训名单”的来源,由独立字典承载,严禁共用同一模糊枚举。
- 注释修改为:
- 验证方式:审查注释与文档的一致性。
- 是否解决:已彻底解决。
R2-04: Preflight 升级为真正 Phase 0.5 精确骨架校验
- 问题:原
000_preflight.sql仅做了表存在性、行数和少量代表性约束判断,未能覆盖完整的 Phase 0.5 物理结构骨架,若存在“少一个正确FK + 多一个错误FK”的对冲情况可能假阳性通过。 - 原实现:部分抽检 + 触发器循环判断。
- 修改文件:
- 修改后实现:
采用 CTE
VALUES(...)构造预期基线集合,与系统目录做全集合差集比对:- 14 个旧表 PK (table_name + constraint_name + column_name)
- 6 个 Phase 0.5 identity 自增主键 (table_name + column_name + is_identity = 'YES')
- 7 组业务 UNIQUE 约束 (table_name + constraint_name + column_list)
- 24 组业务 FK 约束 (table_name + constraint_name + column_name + foreign_table_name + foreign_column_name)
- 9 个 update_time 触发器 (table_name + trigger_name)
- 行数基线:
train_teacher精确 1 行,其余 13 张旧表精确 0 行 - 8 张 V2 表均不得存在,public.sys_* 表零受损
- 任何 missing / unexpected / definition mismatch 立即抛出
RAISE EXCEPTION。
- 验证方式:对比
rollback/000_phase05_exact_schema.sql校验集合完备性。 - 是否解决:已彻底解决。
R2-05: 010_verify 升级为“定义级验收”
- 问题:原 010 验收脚本主要核验对象名称存在性,对约束内部的具体列排序、外键删除规则、CHECK 表达式逻辑等未做定义级校验。
- 原实现:检查约束名称与
count(*) = 26等数量判断。 - 修改文件:
- 修改后实现:
- UNIQUE 验收:必须断言
table_name+constraint_name+column_list(如train_enrollment(plan_id, student_id)); - FK 验收:必须断言源表、源列、目标表、目标列及
delete_rule = 'NO ACTION',严禁 CASCADE; - CHECK 验收:按约束名逐项检索表达式,校验包含预期表达式(时间先后、场地二选一、权重0~100、满分>0、得分非负、时长非负、单号系统联动、容量>0);
- Identity 验收:逐项确认 12 张业务表的主键列名且
is_identity = 'YES'; - Index 验收:确认 3 组排课复合时间列排序;确认
uq_idx_study_source_event的(source_system, source_event_id)及双非空 WHERE 条件; - 默认值验收:强断言
accommodation_status默认为 0,强断言 6 个业务选择型字段无默认值。
- UNIQUE 验收:必须断言
- 验证方式:静态代码比对与逻辑推演。
- 是否解决:已彻底解决。
R2-06: 正式迁移对象删除 IF NOT EXISTS
- 问题:V2 是一次从已知 Phase 0.5 基线出发的严格版本迁移,已有 Preflight 保证环境纯净。若正式建表或建索引保留
IF NOT EXISTS,一旦因历史残留存在同名但结构错误的脏对象,DDL 将静默跳过真正正确的对象创建,掩盖严重隐患。 - 原实现:
CREATE TABLE IF NOT EXISTS train_...(002)ADD COLUMN IF NOT EXISTS ...(003)CREATE INDEX IF NOT EXISTS ...(006)
- 修改文件:
- 修改后实现:
- 002 中 8 张新增表全部改为严格
CREATE TABLE; - 003 中新增字段全部改为严格
ADD COLUMN; - 006 中所有索引全部改为严格
CREATE INDEX与CREATE UNIQUE INDEX; - 仅保留防御性卸载旧对象的
DROP CONSTRAINT IF EXISTS和DROP TRIGGER IF EXISTS。
- 002 中 8 张新增表全部改为严格
- 验证方式:全局 grep 检查
IF NOT EXISTS出现位置并逐一确认合理性。 - 是否解决:已彻底解决。
R2-07: 增加 DDL Transaction Probe Gate
- 问题:迁移执行契约依赖事务的原子性(
BEGIN ... COMMIT / ROLLBACK)。当前环境为 KingbaseES V009R003C018 (database_mode=mysql),需在正式执行 V2 前实证验证当前数据库实例对 DDL 的事务回滚支持能力。 - 原实现:未设立 DDL 事务能力前置探针。
- 修改文件:
- 修改后实现:
- 创建独立的安全探针脚本(作为 Gate A):
- Phase A:
BEGIN -> CREATE TABLE public.__railway_v2_tx_probe -> ALTER TABLE -> ROLLBACK; - Phase B:只读断言
__railway_v2_tx_probe是否存在。若残留则强行抛出RAISE EXCEPTION阻断后续所有迁移; - 绝不读取或修改任何业务表或系统表,仅使用专用临时对象。
- Phase A:
- 在执行契约中将 Gate A 设定为执行流水线第一道强制关卡。
- 创建独立的安全探针脚本(作为 Gate A):
- 验证方式:审查探针脚本的幂等性与零副作用安全性。
- 是否解决:已彻底解决。