最近工作挺忙,已经接近996了,所以博客更新也少了。今天忙里偷闲,分享一个最近遇到的一个数据库设计问题。业务需求是:
- 针对一条人员信息的数据进行审批操作
- 在进行审批时要看到审批前后数据的修改
- 同一人员的审批数据只能存在一条
- 审批通过后数据在正式表中生效
- 审批通过后保存审批结果数据
业务逻辑本身并不复杂,我们可以建一个跟正式表完全相同的临时表来存储修改的数据,再增加一个审批结果来标识这条数据。
假如正式表为:
ID(pk) | INFO1 | info2 | ... |
---|---|---|---|
00001 | test | test | ... |
那么我们临时表可以设计为
ID(pk) | info1 | info2 | ... | AUDIT_RESULT |
---|---|---|---|---|
00001 | updated | updated | ... | pass |
这样的设计符合直觉,实现起来也很简单,但问题是这个方法的扩展性不够好。原因是正式表的字段可能有很多,这些字段的类型也千差万别。假如以后加入了新功能需要对正式表的部分字段进行修改审批,当前的临时表就不能满足了。因为临时表是以id为主键的,如果继续使用临时表,则之前的审批结果就无法保存了。为了满足今后的扩展,临时表需要重新设计。
临时表的基础上加一个字段AUDIT_TYPE ,把AUDIT_TYPE设置为主键。表结构如下:
ID(pk) | AUDIT_TYPE(pk) | INFO1 | INFO2 | ... | AUDIT_RESULT |
---|---|---|---|---|---|
00001 | 01 | updated | updated | ... | pass |
00001 | 02 | updated | updated | ... | reject |
设置AUDIT_TYPE以后就可以区分出各种类型的审批,方便针对其他类似的需求进行扩展。当然实际使用的时候应该考虑业务的要求,如果业务没有潜在的扩展需求用第一个方法也是可行的。
这个设计思路可以推广到其他数据库的设计。每个月备份正式表的数据,我们就可以加一个月份作为联合主键。举个例子:
ID(pk) | MONTH(pk) | INFO1 | INFO2 | ... |
---|---|---|---|---|
00001 | 201801 | test | test | ... |
类似的例子还有很多,这里就不多费口舌了。