4. 数据库设计(下)

义务明细表是合同义务跟踪系统的核心数据实体,它记录了每一条具体合同义务的完整属性。本节将详细拆解义务明细表的字段设计,包括字段类型、长度、约束以及业务含义,确保数据库结构能够支撑后续的动态监控与接口调用。

4.1 义务明细表核心字段清单

义务明细表(obligation_detail)的设计遵循“高内聚、低冗余”原则,每个字段都对应一个明确的业务监控维度。下表列出了所有关键字段及其设计规范:

字段名 数据类型 长度 约束 业务说明
obligation_id BIGINT 20 PK, AUTO_INCREMENT 义务唯一标识,自增主键
contract_id BIGINT 20 FK, NOT NULL 关联合同主表,建立从属关系
obligation_type TINYINT 4 NOT NULL, DEFAULT 0 义务类型:0-付款、1-交付、2-验收、3-质保、4-其他
responsible_person VARCHAR 64 NOT NULL 责任人姓名或工号,用于任务指派
deadline DATE - NOT NULL 截止日期,驱动超期预警
status TINYINT 4 NOT NULL, DEFAULT 0 状态:0-待办、1-进行中、2-已完成、3-已逾期、4-已关闭
completion_percentage DECIMAL 5,2 DEFAULT 0.00 完成百分比,范围 0.00 ~ 100.00
设计要点: 使用 TINYINT 而非 VARCHAR 存储义务类型和状态,可提升查询性能并减少存储空间。业务枚举值在应用层通过常量类或枚举类统一管理,避免数据库与代码的硬编码耦合。

4.2 字段设计深度解析

4.2.1 义务ID与合同ID:主键与外键的协作

  • obligation_id 采用自增 BIGINT,确保高并发场景下主键的唯一性与写入性能。
  • contract_id 作为外键,必须建立索引以加速按合同查询义务列表的 JOIN 操作。
  • 建议在 contract_id 上创建非唯一索引,因为一个合同通常包含多条义务。

4.2.2 义务类型与状态:枚举驱动的业务逻辑

  • obligation_type 决定了义务的监控规则。例如,付款义务需要关联财务凭证号,交付义务需要关联物流单号。
  • status 字段与 deadline 字段联动:当当前日期超过 deadline 且 status 不为“已完成”或“已关闭”时,系统自动将 status 标记为“已逾期”。
  • 状态流转必须遵循有限状态机(FSM)规则,例如“待办”只能进入“进行中”或“已逾期”,不能直接跳转到“已完成”。

4.2.3 完成百分比:精度与业务含义

  • 使用 DECIMAL(5,2) 支持两位小数,满足精细化管理需求(如 87.50%)。
  • 百分比的计算逻辑由后端服务根据子任务完成情况自动更新,不允许前端直接写入。
  • 当 completion_percentage = 100.00 时,系统应自动触发状态变更检查,若满足条件则将 status 更新为“已完成”。

4.3 义务明细表实体关系图

下图展示了义务明细表与合同主表之间的核心关联,以及义务内部字段之间的逻辑依赖关系:

义务明细表实体关系图 合同主表 contract_id (PK) contract_name party_a / party_b 义务明细表 obligation_id (PK) contract_id (FK) obligation_type responsible_person deadline status completion_percentage 1 : N 状态流转规则(FSM) 待办(0) → 进行中(1) → 已完成(2) 待办(0) → 已逾期(3) → 进行中(1) 任何状态 → 已关闭(4) [手动归档] 百分比联动规则 completion_percentage = 100% → 自动检查 status → 若满足条件则置为“已完成”

4.4 字段设计避坑指南

常见设计陷阱:
  • 使用浮点类型存储百分比: FLOAT/DOUBLE 存在精度误差,应使用 DECIMAL 确保计算准确。
  • 截止日期使用 DATETIME 而非 DATE: 义务截止通常只精确到日,使用 DATE 可避免时间部分带来的歧义和索引效率下降。
  • 状态字段允许空值: 义务状态必须有明确初始值(待办),不应允许 NULL,否则会导致业务逻辑判断混乱。
  • 缺少责任人索引: 按责任人查询待办义务是高频操作,应在 responsible_person 字段上建立索引。

4.5 建表 SQL 参考

以下为义务明细表的完整建表语句,包含主键、外键、索引及默认值约束:

CREATE TABLE `obligation_detail` (
  `obligation_id`       BIGINT(20)    NOT NULL AUTO_INCREMENT  COMMENT '义务唯一ID',
  `contract_id`         BIGINT(20)    NOT NULL                 COMMENT '关联合同ID',
  `obligation_type`     TINYINT(4)    NOT NULL DEFAULT 0       COMMENT '义务类型:0-付款,1-交付,2-验收,3-质保,4-其他',
  `responsible_person`  VARCHAR(64)   NOT NULL                 COMMENT '责任人',
  `deadline`            DATE          NOT NULL                 COMMENT '截止日期',
  `status`              TINYINT(4)    NOT NULL DEFAULT 0       COMMENT '状态:0-待办,1-进行中,2-已完成,3-已逾期,4-已关闭',
  `completion_percentage` DECIMAL(5,2) NOT NULL DEFAULT 0.00  COMMENT '完成百分比 0.00~100.00',
  `create_time`         DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time`         DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`obligation_id`),
  KEY `idx_contract_id` (`contract_id`),
  KEY `idx_responsible_person` (`responsible_person`),
  KEY `idx_deadline` (`deadline`),
  KEY `idx_status` (`status`),
  CONSTRAINT `fk_contract` FOREIGN KEY (`contract_id`) REFERENCES `contract_main` (`contract_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合同义务明细表';
索引策略说明: 为 contract_id、responsible_person、deadline、status 分别建立单列索引,可覆盖绝大多数查询场景。若后续出现复合查询性能瓶颈,可考虑添加联合索引,例如 (responsible_person, status, deadline) 用于“某责任人的待办义务按截止日期排序”查询。