Files
railwaysystem/docs/database-v2/05_execution_contract.md
T

93 lines
7.5 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 迁移执行契约 (Execution Contract)
> **适用范围**:数据库 V2 迁移在测试环境与未来生产环境中的正式执行规范
> **技术基线**:KingbaseES V009R003C018 (`database=training`, `schema=public`, `database_mode=mysql`)
> **核心原则**:**双门禁强准入 (Gate A/B)、单文件显式事务、纯 SQL 执行器兼容、失败即刻熔断**
---
## 1. 执行器与客户端兼容规范
为杜绝因客户端专有指令导致的语法中断或解析失败,物理迁移 SQL 已全面实施去客户端化:
1. **纯标准 SQL 语法**:
- 彻底移除 `\echo`、`\set`、`DELIMITER` 等特定客户端(如 psql/ksql/mysql)专有元命令;
- 进度提示统一采用 PL/pgSQL 标准内置机制:`RAISE NOTICE '...'`;
- 失败阻断统一采用标准异常中断:`RAISE EXCEPTION '...'`。
2. **多客户端适配兼容性**:
- 支持通过 Kingbase 原生命令行工具 `ksql` 执行:`ksql -U kingbase -d training -f xxx.sql`;
- 支持通过通用数据库客户端(如 DBeaver、Navicat、DataGrip)以“执行脚本文件”模式执行;
- 支持通过自动化运维流水线或 JDBC Runner 顺序执行。
---
## 2. 迁移编排流水线与事务边界
迁移必须严格按照以下阶段顺序串行执行。**任何前置 Gate 失败或 Stage 报错,必须立即停止,绝对禁止跳步骤继续!**
```mermaid
graph TD
GateA[Gate A: 000_tx_capability_probe.sql] -->|PASS| GateB[Gate B: 000_preflight.sql]
GateB -->|PASS| S1[Stage 1: 001_backup_current_schema.sql]
S1 --> S2[Stage 2: 002_create_new_tables.sql]
S2 --> S3[Stage 3: 003_alter_master_tables.sql]
S3 --> S4[Stage 4: 004_rebuild_business_tables.sql]
S4 --> S5[Stage 5: 005_constraints.sql]
S5 --> S6[Stage 6: 006_indexes.sql]
S6 -.->|跳过字典初始化| S7[Stage 7: 008_migrate_teacher.sql]
S7 --> S8[Stage 8: 009_drop_legacy_score.sql]
S8 --> S9[Stage 9: 010_verify.sql]
S9 --> Done[迁移完成 交付测试验收]
```
### 详细阶段契约表
| 阶段 | 脚本文件 | 事务边界 | 失败处理与影响 |
| :---: | :--- | :---: | :--- |
| **Gate A** | [`000_tx_capability_probe.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/000_tx_capability_probe.sql) | 探针显式事务 | **强阻断**:实证探测实例 DDL 回滚能力。若表残留立即抛出异常并中止,严禁进入后续阶段 |
| **Gate B** | [`000_preflight.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/000_preflight.sql) | 纯只读骨架断言 | **强阻断**:集合差集校验 14旧表PK、24旧表FK、7组UNIQUE、6个identity主键、9触发器与行数基线,任何不符立即中止 |
| **Stage 1** | [`001_backup_current_schema.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/001_backup_current_schema.sql) | `BEGIN ... COMMIT` | **强阻断**:全量快照 14 张表至 `bak_v1_*`;若已存在备份表则阻断;失败全单回滚 |
| **Stage 2** | [`002_create_new_tables.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/002_create_new_tables.sql) | `BEGIN ... COMMIT` | 创建 V2 新增 8 张表;严禁 `IF NOT EXISTS`;失败事务回滚,新表全部撤销 |
| **Stage 3** | [`003_alter_master_tables.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/003_alter_master_tables.sql) | `BEGIN ... COMMIT` | 调整 8 张主数据表;移除旧触发器与阻断外键,添加 V2 新列;失败事务回滚 |
| **Stage 4** | [`004_rebuild_business_tables.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/004_rebuild_business_tables.sql) | `BEGIN ... COMMIT` | 断言 0 行后重构 5 张业务表;失败事务回滚,原表结构保持不变 |
| **Stage 5** | [`005_constraints.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/005_constraints.sql) | `BEGIN ... COMMIT` | 集中注入 13 组 UNIQUE、26 组 FK (NO ACTION)、9 组 CHECK;失败事务回滚 |
| **Stage 6** | [`006_indexes.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/006_indexes.sql) | `BEGIN ... COMMIT` | 创建外键索引、排课多维复合索引及双非空部分唯一索引;失败事务回滚 |
| **-** | [`007_dicts.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/007_dicts.sql) | - | **【本迁移流水线跳过不执行】** 业务字典留待应用接口及权限配置阶段接入 |
| **Stage 7** | [`008_migrate_teacher.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/008_migrate_teacher.sql) | `BEGIN ... COMMIT` | 迁移并断言教师 1 行数据,固化 NOT NULL,安全清理旧列;失败事务回滚 |
| **Stage 8** | [`009_drop_legacy_score.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/009_drop_legacy_score.sql) | `BEGIN ... COMMIT` | 断言 0 行后下线旧表 `train_score_info`;失败事务回滚,旧表完好保留 |
| **Stage 9** | [`010_verify.sql`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/010_verify.sql) | 纯只读深度断言 | **强阻断**:定义级全量验收 21 表、UNIQUE 列清单、FK NO ACTION、CHECK 表达式、12 Identity、默认值及系统表零受损 |
---
## 3. 已冻结的核心架构决策 (技术负责人正式拍板)
在数据库 V2 迁移及后续业务开发中,以下两项设计原则已作为**已冻结架构决策**执行:
### 决策 A:排课与住宿并发控制
- **决策结论**:一期**绝不引入**外部排课引擎或复杂时间区间调度框架。
- **技术实现**:
1. 数据库层面配置针对性复合检索索引(`idx_lesson_teacher_time`, `idx_lesson_classroom_time`, `idx_lesson_site_time`);
2. 业务层面由排课与住宿分配 Service 在单个本地事务内执行区间交叉检索;
3. 必要时使用 `SELECT ... FOR UPDATE` 悲观锁锁定宿位或教师日历,保障并发一致性。
### 决策 B:跨培训班核心业务一致性 (防串班)
- **决策结论**:**绝不**为了防止串班而在考勤、成绩、自主学习时长等细粒度业务表冗余增加 `plan_id` 反范式列,严格保持数据库 V2 的 3NF 规范化设计。
- **技术实现**:
由应用层业务 Service 在写入和处理业务时强制校验一致性链条:
- `checkin.enrollment.plan_id = lesson.plan_course.plan_id` (考勤打卡班级一致)
- `student_score.enrollment.plan_id = score_item.plan_id` (成绩录入班级一致)
- 当 `score_item.plan_course_id IS NOT NULL` 时,`score_item.plan_id = plan_course.plan_id`
- `study_duration.enrollment.plan_id = plan_course.plan_id` (学习记录班级一致)
任何不一致均由 Service 抛出业务异常阻断入库。
---
## 4. 失败处理与应急回滚规范
1. **单点失败即刻熔断**:
- 若流水线中任何一个脚本执行报错,**严禁跳过该步骤继续执行后续脚本**!
- 单文件具备 `BEGIN ... COMMIT`,当前失败脚本的所有物理改动会自动回滚撤销。
2. **应急回滚调用准则**:
- 若在 Stage 2 ~ Stage 8 中途发生不可调和的异常,必须立即暂停,并由 DBA 评估调用 [`rollback/`](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/sql/train/v2/rollback/) 脚本;
- 回滚流水线严格按照:`001_rollback_new_tables.sql` -> `002_rollback_modified_tables.sql` -> `003_restore_legacy_score.sql` 倒序执行;
- 回滚完毕后,必须运行 `000_preflight.sql` 校验是否完全恢复至 Phase 0.5 精确基线。