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

144 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`(已入住)。而正式业务流程为:名单确定 -> 报到前宿舍预分配 -> 学员报到核验 -> 展示已分配宿舍 -> 实际入住。若默认直接为已入住,与真实业务全生命周期相悖。
- **原实现**:
```sql
accommodation_status SMALLINT NOT NULL DEFAULT 1
```
- **修改文件**:
- [`002_create_new_tables.sql`](../../RuoYi-Vue/sql/train/v2/002_create_new_tables.sql#L142)
- [`010_verify.sql`](../../RuoYi-Vue/sql/train/v2/010_verify.sql)
- **修改后实现**:
```sql
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`
- **修改文件**:
- [`002_create_new_tables.sql`](../../RuoYi-Vue/sql/train/v2/002_create_new_tables.sql)
- [`004_rebuild_business_tables.sql`](../../RuoYi-Vue/sql/train/v2/004_rebuild_business_tables.sql)
- [`010_verify.sql`](../../RuoYi-Vue/sql/train/v2/010_verify.sql)
- **修改后实现**:
上述 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`(学员长期主档来源)发生混淆。
- **原实现**:
```sql
COMMENT ON COLUMN train_enrollment.source_type IS '进入本期培训名单的来源 (1:组织指派, 2:自主报名, 3:单位推荐, 4:统一调训)';
```
- **修改文件**:
- [`002_create_new_tables.sql`](../../RuoYi-Vue/sql/train/v2/002_create_new_tables.sql#L94)
- [`04_risk_review.md`](04_risk_review.md)
- [`01_table_inventory.md`](01_table_inventory.md)
- **修改后实现**:
- 注释修改为:
```sql
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”的对冲情况可能假阳性通过。
- **原实现**:部分抽检 + 触发器循环判断。
- **修改文件**:
- [`000_preflight.sql`](../../RuoYi-Vue/sql/train/v2/000_preflight.sql)
- **修改后实现**:
采用 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` 等数量判断。
- **修改文件**:
- [`010_verify.sql`](../../RuoYi-Vue/sql/train/v2/010_verify.sql)
- **修改后实现**:
- **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_create_new_tables.sql`](../../RuoYi-Vue/sql/train/v2/002_create_new_tables.sql)
- [`003_alter_master_tables.sql`](../../RuoYi-Vue/sql/train/v2/003_alter_master_tables.sql)
- [`006_indexes.sql`](../../RuoYi-Vue/sql/train/v2/006_indexes.sql)
- **修改后实现**:
- 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 事务能力前置探针。
- **修改文件**:
- 新增:[`RuoYi-Vue/sql/train/v2/000_tx_capability_probe.sql`](../../RuoYi-Vue/sql/train/v2/000_tx_capability_probe.sql)
- [`05_execution_contract.md`](05_execution_contract.md)
- **修改后实现**:
- 创建独立的安全探针脚本(作为 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 设定为执行流水线第一道强制关卡。
- **验证方式**:审查探针脚本的幂等性与零副作用安全性。
- **是否解决**:**已彻底解决**。