9.8 KiB
9.8 KiB
09 数据库持久化模型方案比选与设计基线 (Database Mapping Proposal)
设计红线:本轮仅做架构比选与实体设计,禁止执行任何 DDL 脚本或修改生产数据库。 设计原则:面向未来多锁扩展与多厂商接入,保持本地宿舍台账的纯粹性,业务授权与硬件异步对账分层治理。
1. 外部资源映射模型比选 (RESOURCE_MAPPING_RECOMMENDATION)
1.1 映射关系现实挑战
- 一个房间可能安装多把锁:如公寓入户门锁与套内自习室/卧室锁,单一房间可能绑定 0、1 或多把智能门锁。
- 外部厂商多变性:DMS 属于第三方 SaaS/IoT 平台,未来房建公寓段若自建门禁或改用国铁集团集采设备,字段名与标识均可能改变。
- 资源解绑与重绑需求:房间门锁损坏更换后,仅涉及设备 SN 变更,不应引起本地宿舍主记录的历史数据污染。
1.2 两种设计方案对比
| 评估维度 | 方案一:在 train_dormitory_info 直接加列 |
方案二:独立 train_external_resource_mapping 表 (推荐) |
|---|---|---|
| 表结构改动 | 在宿管表直接加 dms_place_id, dms_lock_id, dms_lock_sn 等 |
物理宿舍表保持零污染;新建独立的外部资源映射关联表 |
| 一房多锁支持 | 无法支持(单行只能记录一把锁的 SN 和 ID) | 天然支持(一个 dorm_id 可对应多行锁具映射记录) |
| 多厂商与扩展性 | 差(换厂商需继续加字段,如 hik_channel_id) |
优秀(通过 vendor_code 区分不同厂商,复用通用映射模型) |
| 设备更换生命周期 | 弱(直接覆写破坏审计历史) | 强(可标记旧锁为 DEPRECATED,新增新锁映射) |
| 迁移与实施成本 | 极低 | 低(新增一张轻量级关联表) |
1.3 外部资源映射推荐方案结论
采纳方案二:建立独立的外部资源映射模型。
- 概念模型结构设计:
train_external_resource_mapping ├── mapping_id BIGINT (主键) ├── local_resource_type VARCHAR(32) ('DORMITORY_ROOM', 'DORMITORY_LOCK') ├── local_resource_id VARCHAR(32) (关联本地 dorm_id) ├── vendor_code VARCHAR(32) ('DMS_IOT') ├── external_project_id BIGINT (DMS 租户 projectId) ├── external_parent_id BIGINT (DMS 楼栋/楼层 ID) ├── external_place_id BIGINT (DMS 房间 placeId) ├── external_device_id BIGINT (DMS 门锁 lockId) ├── hardware_sn VARCHAR(64) (门锁硬件 SN / hardwareId) ├── mapping_status SMALLINT (1: 已绑定有效, 0: 待核对/失效) ├── last_sync_time TIMESTAMP (最近一次从 DMS 同步元数据的时间) └── [标准审计列]
2. 门禁授权与操作模型三大方案深度比选
2.1 方案架构与评估矩阵
| 评估维度 | 方案 A: 改造并继续扩展 train_dorm_auth |
方案 B: train_dorm_auth 收敛为业务授权 + 独立 train_external_operation (推荐) |
方案 C: 新建 train_door_authorization + train_external_operation |
|---|---|---|---|
| 模型设计说明 | 在现有的 train_dorm_auth 表中强行塞入 lock_id, dms_key_id, operation_id, password 等列 |
保留并对齐数据库 V2 的 train_dorm_auth 作为门禁授权主表;新建 train_external_operation 承载所有异步轮询与重试流水 |
彻底废除 train_dorm_auth,重新设计全套中立命名的门禁授权与外部操作表 |
| 一期开发复杂度 | 低(改单表) | 适中(改主表结构 + 建流水表) | 略高(需处理原有表废弃与实体完全重构) |
| 语义与职责清晰度 | 严重混乱(业务授权与设备单次请求纠缠,无法表达异步过程) | 良好(业务授权状态与设备异步任务彻底解耦) | 极优(概念完全脱离人脸/宿舍局限) |
| 一房多锁支持能力 | 无法支持(accommodation_id 唯一约束导致无法为同一个住宿下发多把锁) |
支持(主表唯一约束调整为 (accommodation_id, device_mapping_id)) |
支持(原生复合设计) |
| 异步状态与重试审计 | 丢失历史(每次重试都会覆写 last_error 和 operation_id) |
完整保留(流水表每次调用追加一行,多次轮询与超时全量追踪) | 完整保留 |
| 历史兼容与代码改动 | 兼容性最高,但长期技术负债巨大 | 平衡性最佳(沿用 V2 数据库迁移成果,仅修正 Java 实体脱节) | 需调整较多已有引用类名 |
3. 推荐采纳模型设计基线 (DOOR_AUTH_MODEL_RECOMMENDATION)
综合考虑沈阳房建公寓段学员管理系统目前所处的正式 Release 阶段与 V2 数据库已经上线的实际情况,推荐采纳【方案 B】(业务授权主表收敛 + 异步操作流水表解耦)。
3.1 实体一:门禁业务授权主模型 (TrainDormAuth / 业务授权主表)
承担职责:表达某个学员住宿事实在某把门锁上的长期通行权限状态。
auth_id: BIGINT, PKaccommodation_id: BIGINT, 外键关联train_accommodation(业务事实真源)mapping_id: BIGINT, 关联train_external_resource_mapping(目标门锁)credential_type: VARCHAR(20) ('ONLINE_PASSWORD', 'ONLINE_CARD')credential_mask: VARCHAR(50) (脱敏凭据摘要,如 '34' 或 '244B')external_key_id: BIGINT (DMS 返回的钥匙实体 ID,用于注销撤权)auth_start: TIMESTAMP (权限生效起始时间)auth_end: TIMESTAMP (权限失效截止时间)auth_status: SMALLINT (0:待下发, 1:下发中, 2:已生效, 3:下发失败, 4:撤销中, 5:已注销, 6:撤销失败)grant_version: INT (授权版本号,换房或重新下发时自增,保障本地幂等)[标准审计列](create_by,create_time,update_by,update_time)
3.2 实体二:外部异步操作流水模型 (TrainExternalOperation / 异步操作流水表)
承担职责:跟踪向 DMS 派发的每一次具体 HTTP 异步任务的生命周期与轮询轨迹。
operation_local_id: BIGINT, PKauth_id: BIGINT, 外键关联授权主表business_action: VARCHAR(32) ('GRANT_PASSWORD', 'REVOKE_PASSWORD', 'GRANT_CARD', 'REVOKE_CARD')vendor_code: VARCHAR(32) ('DMS_IOT')dms_operation_id: VARCHAR(64) (DMS 返回的 32 位 UUID 操作流水号)dms_request_type: INT (DMS 数字请求类型,如 1=下发密码, 3=删除密码)hardware_id: VARCHAR(64) (门锁硬件 SN)operation_status: VARCHAR(20) ('ACCEPTED', 'UNDONE', 'SUCCESS', 'FAILED', 'TIMEOUT')poll_count: INT (已轮询次数,初始为 0,上限通常为 3)next_poll_time: TIMESTAMP (调度器下次拉取状态的时间,初始为request_time + 10s)request_time: TIMESTAMP (向 DMS 发起请求的时间)complete_time: TIMESTAMP (DMS 返回终态的时间)error_code&error_message: VARCHAR (错误摘要)sanitized_response: VARCHAR(1000) (脱敏后的响应快照)[标准审计列]
4. 实施阶段演进建议
在后续 R.3B 实施阶段,数据访问层的演进步骤建议为:
- 第一步:重构修复 Java 实体类
TrainDormAuth.java,彻底移除已弃用的student_id,plan_id,dorm_id字段,使其与已存在的 Kingbase 物理表字段完全对齐。 - 第二步:创建
train_external_resource_mapping与train_external_operation迁移脚本(遵循系统标准 Liquibase/Flyway 规范)。 - 第三步:通过 Spring Data / MyBatis-Plus 完成三表关联映射。
4.1 Wave 0 Implementation Result (第一步已正式交付)
- 已完成事项:
- 重构并修复
TrainDormAuth.java,彻底废弃了向train_dorm_auth写入student_id,plan_id,dorm_id,bed_no,create_user的历史假设。 - 补齐
TrainAccommodation.java、TrainAccommodationMapper.java、TrainAccommodationMapper.xml、ITrainAccommodationService以及TrainAccommodationServiceImpl,完全对齐 V2 生产物理结构。 - 严格禁止在 Wave 0 中引入任何 DMS 物理字段(如
lock_id,place_id,operation_id),保持 Vendor-Neutral 纯净业务边界。 - 生产 Migration 检查:
MIGRATION_REQUIRED = NO,生产数据库零写入、零变更。
- 重构并修复
4.2 Wave 0.1 Accommodation History Migration (006 迁移方案与基数冻结)
- 领域基数与物理约束演进:
- 历史模型:
Enrollment 1:N Accommodation History,允许学员由于调房等产生多条住宿历史。 - 唯一性收敛:
Enrollment 1:0..1 Active Accommodation,原全局唯一约束UNIQUE(enrollment_id)阻碍了历史留痕,演进为针对有效状态(accommodation_status IN (0, 1))的局部唯一索引。 - 授权关联:
Accommodation 1:0..1 DoorAuthorization,门禁授权强引用住宿实体。 - 时间范围特性:
TIME_RANGE_SUPPORT = LIMITED,当前物理表仅有assigned_time,未扩展起止时间列。
- 历史模型:
- 006 Migration 脚本设计与验证:
- 文件路径:
RuoYi-Vue/sql/system/kingbase/006_accommodation_history_constraint.sql - 安全编号:
006(避免与 R.2 占用的 004/005 冲突)。 - 执行安全机制:
- 前置重复数据检查:存在并发违规 active 记录时直接
RAISE EXCEPTION阻断。 - 严格条件 DROP:仅当原约束
uq_accommodation_enroll确认为UNIQUE (enrollment_id)时执行 drop。 - 创建局部唯一索引:
CREATE UNIQUE INDEX IF NOT EXISTS uq_accommodation_enroll_active ON train_accommodation (enrollment_id) WHERE accommodation_status IN (0, 1); - 幂等防护:重复执行幂等安全。
- 前置重复数据检查:存在并发违规 active 记录时直接
- 生产执行纪律:本脚本已在单元/契约测试中完成全量静态与逻辑校验,禁止在生产库执行。
- 文件路径: