Files
railwaysystem/docs/codebase-audit/14_database_code_diff.md
wangzhibiao fb00f67d3b docs(审计): 完成Phase 0工程与数据库基线核验
记录当前Git开发基线、Kingbase真实表结构、培训数据与权限状态。

补充数据库与代码差异、只读兼容性验证及PRD V1.0核心对象映射,未包含业务代码或数据库修改。
2026-09-14 00:36:53 +08:00

11 KiB
Raw Permalink Blame History

Phase 0:设计文档、实时Kingbase与代码三方差异

业务判断以 doc/RailwaySystem 智慧培训系统一期 PRD V1.0.md 为最高依据。原始表设计只用于说明V1数据库来源,不能否定PRD V1.0已经确认的新业务对象。

1. 三方总览

14个 Mapper XML 的 resultMap 字段数与实时表列数逐表一致:157个实际列均在对应 Mapper映射中出现。当前 Entity/Mapper与旧14表可以静态对接;主要问题来自旧表模型与PRD V1.0业务对象不一致,以及若依系统表schema冲突。

表 原设计文档 实际Kingbase Entity / Mapper 是否一致 主要差异
train_teacher 12列,t_id varchar(20) 12列,t_id varchar(32),PK,更新时间触发器,1行 12列全映射,TrainTeacher 部分一致 ID长度不同;PRD不再强制院系/高校职称,缺启停等培训字段
train_student 12列,s_id varchar(20) 12列,s_id varchar(32),PK,更新时间触发器,0行 12列全映射,TrainStudent 部分一致 ID长度不同;缺加密身份证、人脸关联、培训型主档字段
train_course 14列 14列,PK,更新时间触发器,0行 14列全映射,TrainCourse 字段一致 附件/模型为文本列;PRD要求可选择教学资源对象
train_class_plan 14列,单一c_id/t_id 14列,c_id/t_id均NOT NULL且有FK,0行 14列全映射,TrainClassPlan 旧模型一致 与PRD一班多课、课次教师关系直接冲突;缺报到截止规则
train_dormitory_info 11列 11列,房间组合UNIQUE,更新时间触发器,0行 11列全映射 字段一致 只有楼栋+房间汇总,无楼层、床位、男女属性
train_dorm_auth 12列,INT自增 12列,bigint identity,3个FK,学员/计划UNIQUE,0行 12列全映射,Long + generated keys 语义部分一致 住宿安排与门禁授权耦合;bed_no是自由文本
train_classroom_info 9列 9列,PK,更新时间触发器,0行 9列全映射 一致 基础对象符合PRD;排课关系应由课次表达
train_training_site 10列 10列,PK,更新时间触发器,0行 10列全映射 一致 基础对象可留;site_device为文本而非资源关系
train_class_report 11列,INT自增 11列,bigint identity,5个FK,计划/学员UNIQUE,0行 11列全映射 旧模型一致 应基于参训关系;报到行混入宿舍/教室/场地分配
train_electronic_board 14列 14列,PK,SN唯一,教室/计划FK,0行 14列全映射 旧模型一致 缺设备名称/接口配置;直接绑计划不能表达当前课次
train_student_checkin 10列,INT自增 10列,bigint identity,4个FK,旧课次组合UNIQUE,0行 10列全映射 旧模型一致 无lesson_id和参训关系;起止时间重复保存;没有签到/签退事件模型
train_score_info 10列,固定三类成绩 10列,bigint identity,3个FK,计划/课程/学员UNIQUE,0行 10列全映射 旧模型一致 被PRD“成绩项目+权重+学员得分”正式替代
train_study_duration 9列,INT自增 9列,bigint identity,3个FK,0行 9列全映射 一致 PRD需参训关系、学习内容/来源和可幂等接入信息
train_student_portrait 9列,INT自增 9列,bigint identity,学员/计划UNIQUE,0行 9列全映射 基础一致 与PRD简单画像接近;需参训关系和雷达展示所需基础指标

2. 旧设计与实际Kingbase的结构差异

2.1 类型映射

  • 设计 DATETIME 在Kingbase实际为 timestamp。
  • 设计 TINYINT 在实际为 smallint。
  • 设计6个 INT AUTO_INCREMENT 主键在实际为 bigint GENERATED BY DEFAULT AS IDENTITY。
  • train_teacher.t_id、train_student.s_id 由设计的 varchar(20)扩大为实际 varchar(32)。
  • numeric(5,2)、numeric(8,2) 精度与设计一致。

这些类型差异与当前 Java Date、Long、BigDecimal、String 基本兼容。

2.2 实际约束超过设计文本

实时库明确存在24个外键,以及以下业务唯一约束:

  • 报到:plan_id + student_id
  • 宿舍授权:student_id + plan_id
  • 宿舍房间:dorm_building + dorm_room
  • 班牌:board_sn
  • 成绩:plan_id + c_id + student_id
  • 签到:plan_id + c_id + student_id + lesson_start_time
  • 画像:student_id + plan_id

这些约束未体现在 Entity注解或业务校验中,错误主要由数据库返回。除主键/唯一索引外,外键列没有额外非唯一索引。

2.3 更新时间

教师、学员、课程、计划、宿舍、宿舍授权、教室、场地、班牌9张表有UPDATE触发器维护 update_time。部分 ServiceImpl同时设置更新时间,形成数据库与应用双重维护。

3. 一班多课与课次迁移影响

当前结构

train_class_plan
├── c_id NOT NULL -> train_course
└── t_id NOT NULL -> train_teacher

这会把“培训班”“本期课程”“具体授课安排”压在一行中。

PRD V1.0要求的初步迁移方向

开班计划
↔ 开班课程
→ 课次(教师、时间、教室或实训场地)
  • train_class_plan保留培训班核心信息。
  • c_id对应的信息迁入独立“开班课程”关系,一个计划可多条。
  • t_id不应继续代表整个培训班唯一教师;PRD将教师安排到具体课次。
  • 计划应补充开班级报到截止规则。
  • 当前 train_class_plan 为0行,实时库不存在需要搬迁的历史计划;这降低数据风险,但不消除 Controller、页面、Mapper和外键改造范围。

本报告不确定最终表名、主键或DDL。

4. 参训关系缺口与迁移影响

当前没有独立 student + plan 参训关系。以下6张表重复保存两者:

当前表 重复字段 新增参训关系后的初步引用对象 当前行数
train_dorm_auth student_id + plan_id 住宿安排/门禁授权所属参训人 0
train_class_report student_id + plan_id 报到所属参训人 0
train_student_checkin student_id + plan_id 考勤所属参训人 0
train_score_info student_id + plan_id 成绩所属参训人 0
train_study_duration student_id + plan_id 学习记录所属参训人 0
train_student_portrait student_id + plan_id 画像所属参训人 0

新增参训关系后,上述对象可以引用参训关系,避免每个模块独立解释学员在本期的资格和状态。同一学员/计划应由参训关系保证唯一。

当前6张表均为空,没有现存业务行需要转换。若数据库V2前产生数据,迁移时必须先按唯一的 student_id + plan_id 生成参训记录,再把报到、考勤、成绩、学习、画像、住宿/授权关联到相应参训记录。

5. lesson_id 对现有数据和代码的影响

当前签到

train_student_checkin 用:

plan_id + c_id + student_id + lesson_start_time

模拟课次身份,并保存 lesson_end_time;唯一约束也以这组字段为基础。

加入正式课次后的影响

  • 签到/考勤需要引用课次和参训关系,旧 plan_id/c_id/lesson_start_time/lesson_end_time 不再承担课次主键作用。
  • train_class_plan.t_id 中的教师关系应进入课次。
  • 教室和实训场地应由课次安排,不应继续由 train_class_report.alloc_classroom_id/alloc_site_id 作为学员报到分配。
  • 班牌保留与教室关系;当前展示内容应由教室在当前时段的课次决定,bind_plan_id不能覆盖多班多课排期。
  • Controller、查询条件、前端签到表单、唯一约束、统计维度和Mock班牌接口都会受影响。
  • 当前计划、签到、教室、场地和班牌表均为0行,不存在历史课次数据;未来迁移不能只凭相同起止时间推断课次,需在产生数据前冻结V2。

6. 宿舍:资源、床位、住宿安排、门禁授权

当前表达为:

train_dormitory_info(房间汇总+bed_total/bed_used+门锁SN)
→ train_dorm_auth(学员+计划+房间+bed_no+人脸同步状态)
← train_class_report.alloc_dorm_id(报到记录再次保存房间)

无法完整表达PRD V1.0的:

宿舍资源 → 床位 → 住宿安排 → 门禁授权

初步影响:

  • train_dormitory_info可作为房间资源的来源,但缺楼层、床位实体、男女属性和可靠剩余量。
  • bed_no只是授权表文本,不能单独管理床位占用。
  • train_dorm_auth同时保存住宿事实和设备同步事实,需要拆开看待。
  • train_class_report.alloc_dorm_id与报到前预分配冲突;报到应读取已有住宿安排,而不是创建住宿事实。
  • 这3张表当前均0行,没有现有住宿数据需要搬迁;V2仍需定义从旧授权行拆出住宿安排和门禁授权的规则,以防切换前产生数据。

7. 成绩模型变化

当前字段

train_score_info 固定:

plan_id, c_id, student_id,
course_score, train_score, exam_score,
source_type, source_system, import_time

PRD V1.0目标

培训班 → 成绩项目 → 权重
参训学员 → 成绩项目 → 得分

初步迁移判断

  • course_score、train_score、exam_score 三个固定分数字段将不再是最终模型,未来可能废弃或仅作为迁移来源。
  • plan_id、c_id、student_id 可用于识别旧成绩所属培训班/课程/学员;其中学员+计划应先映射参训关系,课程或其他考核类型应映射成绩项目。
  • source_type、source_system、import_time 的来源追溯语义仍有保留价值,可随具体得分记录迁移。
  • 旧唯一约束 plan_id+c_id+student_id 无法支持同课程多个成绩项目或非课程考核。
  • 当前 train_score_info 精确行数为0,因此不存在真实成绩迁移;从数据角度现在是调整模型的低风险窗口。
  • 代码层仍有 Entity、Mapper、Controller、API、成绩CRUD、课程成绩页和学员成绩页依赖固定三列,因此不能只改数据库。所谓“安全重构”仅指没有生产成绩数据需要保留,不代表代码改造可以无评审完成。

8. PRD V1.0明确不应再作为一期阻塞的旧要求

  • 课程版本、课程审批、草稿/发布/归档、复杂标签、热门、初级/进阶:PRD V1.0明确不做;当前代码缺少这些能力不是一期阻塞。
  • 复杂画像规则引擎:一期只需基础指标、简单标签、雷达图。当前画像表可作为简单结果载体,主要缺参训关系、指标生成和雷达展示。
  • 自动结业规则引擎:一期按培训结束、状态完成、历史数据保留处理。当前不应新增“签到率+成绩+时长”自动结业复杂逻辑。

9. 实时数据库数据对迁移窗口的影响

  • 必须保留/迁移:train_teacher唯一1行教师数据。
  • 当前无历史业务数据:其余13张培训表全部0行,包括成绩、计划、参训相关明细、住宿、签到、学习和画像。
  • 需要保留并重新评审的系统配置:23条培训菜单行。
  • 需要先处理的数据异常:public.sys_role为空,而用户角色、角色菜单关系已有孤儿数据;不能把这些关系直接当作有效权限基线迁入V2。