Files
railwaysystem/docs/database-v2/07_review_round2_changes.md
T

9.3 KiB
Raw Blame History

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 1
    • train_enrollment.accommodation_required: DEFAULT 0
    • train_lesson.venue_type: DEFAULT 1
    • train_student_score.source_type: DEFAULT 1
    • train_student_checkin.checkin_way: DEFAULT 1
    • train_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 定义';
      
    • 文档中明确解耦定义:
      1. train_student.source_type:学员长期主档进入系统的来源(管理员录入/Excel导入/平台同步);
      2. 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 个业务选择型字段无默认值。
  • 验证方式:静态代码比对与逻辑推演。
  • 是否解决:已彻底解决。

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。
  • 验证方式:全局 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 阻断后续所有迁移;
      • 绝不读取或修改任何业务表或系统表,仅使用专用临时对象。
    • 在执行契约中将 Gate A 设定为执行流水线第一道强制关卡。
  • 验证方式:审查探针脚本的幂等性与零副作用安全性。
  • 是否解决:已彻底解决。