再议假删除
TL;DR
“假删除”有一定概率是需求分析不彻底所产生的一种解决方案,应尽可能细化为状态筛选、事件溯源、数据审计、归档备份等具体需求
为什么要假删除?
- 防止误删(无意、恶意)
- 暂时删除
一般实现方法
- 加字段isdeleted,甚至deletedat/deleted_by
- 改写删除接口,填充上述字段;改写查询接口,默认情况下只查询未被假删除的记录(API层、应用内部、数据层……)
gem
如果我真的想删除呢?
- 同时提供真删除和假删除的接口
- 只提供一个删除接口,但根据权限,一些人假删,另一些人真删
- 定期将假删除的记录真删除
- 组合上述做法
修改接口的局限与危害
- 还是有可能绕过默认查询。不管是通过应用层的限制(如ActiveRecord的default_scope),或数据库层的视图,如果没做好权限控制,那么还是有可能通过更底层的方式访问到假删除的记录
- 在底层增加拦截时,上层可能并不知情
级联删除(以具体业务需求为准)
- 子记录要真删除还是假删除还是清空外键?
- 对于deletedat方案,是级联地为子孙表增加deletedat,还是查询时连接父表检查可见性?
- 若假删除子记录,那么还能不能通过它另一父记录查询到它?
- 子记录有没有自己的假删除动作?恢复父记录时怎样判断是否级联恢复子记录?是否需要记录删除原因?
数据校验
- 唯一性校验是否应包含假删除的记录?(离职、重新入职)
- 考虑到未来恢复数据,增加校验规则时要不要也修正假删除的记录?
- 应用层还是数据库层?
性能
- 假删除和真删除的数据分表存储,或分别索引
- 用户配额是否包含假删除的数据
误解需求?
- 状态筛选:枚举字段,aborted/inactive……
- 归档备份:不止转移到另一表中,甚至转移到另一库中,或者导出至其他载体;CDC工具
- 数据审计:不止deletedat/deletedby,连所有updatedat/updatedby操作也记录下来,例如paper-trail-gem/paper_trail([[对比各种日志审计gem]])
- 事件溯源
参考