创建时间: 2026-09-01最后更新: 2026-09-01作者: yangbo(2d5d2525a)
1. 需求
数据建模不是先打开数据库工具创建表,而是先弄清楚系统需要长期保存什么,以及这些数据之间有什么规则。
我们的任务管理系统需要支持这些操作:
- 用户创建项目;
- 项目可以有多名成员;
- 项目中可以创建任务;
- 一条任务可以绑定多个标签;
- 用户只能查看自己参与的项目;
- 任务需要记录状态、优先级和截止时间。
从需求中可以识别出四个核心实体:用户、项目、任务和标签。项目成员、任务标签虽然不是独立存在的业务对象,却需要记录两个实体之间的关系,因此也要建表。这类表通常叫作关联表,关系上的角色、加入时间等属性也保存在这里。
model-overview.txt
1users (1) ----< projects (N) projects.owner_id2users (N) >---< projects (N) project_members3projects (1) ----< tasks (N) tasks.project_id4tasks (N) >---< tags (N) task_tags
图中的 (1) 和 (N) 表示关系两端的数量。例如,一个项目只有一个所有者,一个用户可以拥有多个项目;一条任务也可以绑定多个标签,一个标签又能用于多条任务。
不要把接口 JSON 直接当成数据库模型。接口为了展示方便,可能把项目、负责人和任务嵌套在一个对象里;数据库需要避免重复保存同一事实,并让关系可以被约束和查询。
2. 实体
先确定每个实体自身的属性:
| 实体 | 核心字段 |
|---|---|
| 用户 | id、email、display_name、created_at |
| 项目 | id、owner_id、name、created_at |
| 任务 | id、project_id、task_number、title、status、priority、时间字段 |
| 标签 | id、name |
一个字段应该只表达一个稳定事实。例如把 owner_name 复制到 projects 中,会让用户改名后出现两份不同名称。项目只保存 owner_id,读取时再关联 users。
用户、项目、任务和标签这些核心实体使用没有业务含义的代理键 id。邮箱虽然在当前规则下唯一,但它可能被用户修改,不适合作为其他表长期引用的主键。
关联表不一定需要额外的代理键。project_members 使用 (project_id, user_id) 作为联合主键,task_tags 使用 (task_id, tag_id) 作为联合主键,它们都能直接表达一段关系不能重复出现。
业务唯一性仍然应该通过约束保留:
| 业务规则 | 已有数据库约束 |
|---|---|
| 邮箱在全部用户中唯一 | users_email_key UNIQUE (email) |
| 任务编号在所属项目中唯一 | tasks_project_number_key UNIQUE (project_id, task_number) |
这两条约束已经在前文创建,无需重复执行 ALTER TABLE。代理主键负责稳定引用,唯一约束负责阻止业务重复,两者职责不同。第二条还是联合唯一约束:不同项目可以使用相同任务编号,同一项目内不能重复。
正在验证登录状态
请稍候,验证完成后将继续显示文章内容