附件元数据表应该如何设计?文件和数据库记录如何关联?
简化版
附件一般不直接存数据库大字段,而是把文件放对象存储或文件系统,数据库保存元数据和业务关联。附件表常见字段有文件名、大小、MIME 类型、存储 key、哈希、业务类型、业务 ID、上传人、状态和创建时间。
详细版
附件设计要解决三件事:文件在哪里、属于哪个业务对象、当前是否有效。数据库记录应该保存可追踪的元数据,而不是把文件二进制塞进业务表。
常见设计可以用通用附件表:biz_type + biz_id 关联不同业务;也可以为强业务场景设计专用附件表。文件上传要考虑临时态、绑定态、删除态,避免用户上传成功但业务提交失败后留下孤儿文件。
还要注意权限校验、病毒扫描、文件哈希去重、预签名 URL 过期、软删除和生命周期清理。
完整版教学
一、数据库为什么主要存元数据
文件通常体积大、访问方式特殊,直接存数据库 BLOB 会增加备份、复制、查询和存储成本。多数业务更适合把文件放对象存储,数据库只存索引信息。
例如一张合同 PDF 5MB,100 万份就是 5TB。把它们塞进业务数据库,会让备份恢复和主从复制都非常沉重。
数据库擅长结构化查询和事务关系,不擅长做海量大文件分发。
二、附件表基本字段怎么设计
一个通用附件表可以这样设计:
CREATE TABLE attachment (
id BIGINT PRIMARY KEY,
biz_type VARCHAR(64) NOT NULL,
biz_id BIGINT,
original_name VARCHAR(255) NOT NULL,
storage_key VARCHAR(512) NOT NULL,
mime_type VARCHAR(128),
file_size BIGINT NOT NULL,
file_hash VARCHAR(128),
status VARCHAR(32) NOT NULL,
created_by BIGINT,
created_at DATETIME NOT NULL,
KEY idx_biz (biz_type, biz_id)
);
storage_key 是对象存储里的路径或 key,original_name 是用户看到的文件名,两者不要混用。
三、上传和业务绑定要分状态
常见流程是用户先上传附件,再提交业务表单。如果上传成功但表单没提交,附件就没有业务归属。
所以附件可以有 TEMP、BOUND、DELETED 状态。上传后是临时态,业务提交成功后绑定 biz_type/biz_id,定时任务清理超过 24 小时未绑定的临时文件。
上传文件 -> TEMP
提交业务 -> BOUND
删除业务 -> DELETED 或解除绑定
这能避免对象存储里慢慢堆满孤儿文件。
四、通用关联和专用关联怎么选
biz_type + biz_id 很灵活,一个表能挂合同、工单、报销单。缺点和多态关联类似,数据库无法直接对多个业务表建外键。
如果附件属于核心强业务,例如合同附件、发票附件,专用表会更清晰,能加业务字段和外键约束。
| 方案 | 优点 | 缺点 |
|---|---|---|
| 通用附件表 | 复用高、扩展快 | 完整性靠应用 |
| 专用附件表 | 语义清楚、约束强 | 表更多 |
| 混合方案 | 核心专用,普通通用 | 规范要求高 |
五、权限和安全不能漏
附件下载不能只凭 URL。业务系统要校验用户是否有权限访问对应业务对象,再生成短期预签名 URL 或代理下载。
还要记录文件大小、类型、哈希,限制可上传扩展名,必要时做病毒扫描。用户传的文件名不能直接当存储路径,避免特殊字符和路径污染。
附件表看起来是辅助表,但经常是安全事故入口。
六、常见误区与追问
- 误区:附件表只要存 URL 就够了。 还需要大小、类型、哈希、状态、业务归属和上传人等元数据。
- 误区:文件上传成功就算业务成功。 上传和业务提交是两个阶段,要处理临时附件和孤儿清理。
- 误区:通用附件表一定最好。 强业务附件可能需要专用表和外键约束。
- 追问:如何防止重复文件? 可用文件哈希辅助去重,但要结合权限和业务语义,不能盲目复用。
- 追问:删除业务时附件怎么处理? 可软删除、解除绑定或延迟删除对象存储文件,并保留审计。
七、加强记忆
记忆钩子:附件表是文件的身份证,不是文件本身;身份证要写清楚它是谁、在哪、归谁、还能不能用。
回答这题时按“文件外存、元数据入库、状态绑定、关联方式、安全权限、清理机制”展开。这样能覆盖真实项目里附件最容易出问题的地方。