删除数据时,到底应该硬删除还是软删除?

答案转载地址:https://segmentfault.com/q/1010000003938997/a-1020000003975492

Oren Eini(又名 Ayende Rahien)建议开发者尽量避免数据库的软删除操作,读者可能因此认为硬删除是合理的选择。作为对 Ayende 文章的回应,Udi Dahan 强烈建议完全避免数据删除。

所谓软删除主张在表中增加一个 IsDeleted 列以保持数据完整。如果某一行设置了IsDeleted标志列,那么这一行就被认为是已删除的。Ayende 觉得这种方法“简单、容易理解、容易实现、容易沟通”,但“往往是错的”。问题在于:

删除一行或一个实体几乎总不是简单的事件。它不仅影响模型中的数据,还会影响模型的外观。所以我们才要有外键去确保不会出现“订单行”没有对应的父“订单”的情况。而这个例子只能算是最简单的情况。……

当采用软删除的时候,不管我们是否情愿,都很容易出现数据受损,比如谁都不在意的一个小调整,就可能使“客户”的“最新订单”指向一条已经软删除的订单。

如果开发者接到的要求就是从数据库中删除数据,要是不建议用软删除,那就只能硬删除了。为了保证数据一致性,开发者除了删除直接有关的数据行,还应该级联地删除相关数据。可Udi
Dahan提醒读者注意,真实的世界并不是级联的:

假设市场部决定从商品目录中删除一样商品,那是不是说所有包含了该商品的旧订单都要一并消失?再级联下去,这些订单对应的所有发票是不是也该删除?这么一步步删下去,我们公司的损益报表是不是应该重做了?

没天理了。

问题似乎出在对“删除”这词的解读上。Dahan 给出了这样的例子:

我说的“删除”其实是指这产品“停售”了。我们以后不再卖这种产品,清掉库存以后不再进货。以后顾客搜索商品或者翻阅目录的时候不会再看见这种商品,但管仓库的人暂时还得继续管理它们。“删除”是个贪方便的说法。

他接着举了一些站在用户角度的正确解读:

订单不是被删除的,是被“取消”的。订单取消得太晚,还会产生花费。

员工不是被删除的,是被“解雇”的(也可能是退休了)。还有相应的补偿金要处理。

职位不是被删除的,是被“填补”的(或者招聘申请被撤回)。

在上面这些例子中,我们的着眼点应该放在用户希望完成的任务上,而非发生在某个
实体身上的技术动作。几乎在所有的情况下,需要考虑的实体总不止一个。

为了代替 IsDeleted 标志,Dahan 建议用一个代表相关数据状态的字段:有效、停用、取消、弃置等等。用户可以借助这样一个状态字段回顾过去的数据,作为决策的依据。

删除数据除了破坏数据一致性,还有其它负面的后果。Dahan建议把所有数据都留在数据库里:“别删除。就是别删除。”


这个答案下面有一条评论,我觉得很有道理


根据我自己的实际操作经验来看的话,首先是要有个状态字段,用以标示该条记录是否还有效,正常的业务逻辑都只是通过修改这个状态字段来实现,绝对不能有DELETE语句出现在业务逻辑中。

但同时,我又对每个关系都设置了级联删除的属性,这是因为测试时难免会产生大量的垃圾数据,长此以往会造成整个数据库很脏,因此为了便于清理起见,还是会定期亲自操作删除这些垃圾数据

最近在开发Essay的新版本,在设计数据库时遇到了这个问题,在删除一篇文章时,是否应该从数据库中删除?如果删除,它下面的关联评论咋办?关联标签的咋办?同样的问题还出现在评论回复上,如果原评论已删除,那回复的评论是否一并删除?

最后细想了一下,比较好的做法是软硬删除方式都有,这有点像垃圾箱功能,放到垃圾箱是软删除,清空垃圾箱是硬删除。

最后说一下,我在Essay的新版本上投入了大量的时间,整个项目重写了(这就是为什么github一直未更新的原因),但技术选型没有变。它也不再是一个玩具项目,而是根据工作中的实际经验,开发的一个可用于线上的博客系统,一个完全基于JavaScript开发的同构应用。感兴趣的可以watch下,很快他将会与大家见面

posted @ 2021-10-07 10:18  wmui  阅读(1274)  评论(0编辑  收藏  举报