我应该在外键上使用 onDelete=cascade 吗?

Posted

技术标签:

【中文标题】我应该在外键上使用 onDelete=cascade 吗?【英文标题】:Should I be using onDelete=cascade with my foreign keys? 【发布时间】:2021-10-29 14:34:19 【问题描述】:

相关问题:Foreign key constraints: When to use ON UPDATE and ON DELETE。

我们举个例子,一个公司表和一个用户表,其中包含来自这些公司的人

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

ON DELETE CASCADE:危险:如果您删除表 COMPANY 中的公司行,引擎也会删除相关的 USER。这很危险,但可用于对辅助表进行自动清理(因此它可以是您想要的,但肯定不是 COMPANYUSER 示例)

现在,假设我有多家公司,每家公司都有多个客户。我习惯在每个表上都有一个主自动索引键,并将其用作子表的外键。

那么,既然我的company_id 是自动生成的并且保证是唯一的,那么我将用户表中的外键company_id 设置为onDelete=cascade 有什么危险吗?

显然,我的 GUI 有很多“你确定你确定你真的要删除它吗?操作无法撤消!”

但是,如果我不 onDelete=cascade,那么在我可以DELETE FROM companies WHERE company_id=X 之前,我首先必须DELETE FROM users WHERE company_id=X,这是我一直在做的事情。

我第一次考虑 onDelete=cascade 只是想确定我已经理解了它。当依赖关系树有多个层次时,删除依赖行可能会变得乏味。

另外,由于键是自动索引,它们不会改变,所以我看不出我需要 onUpdate。

[更新] 一个答案是关于删除业务数据。这只是相关问题中的一个示例。

想象一下架构:一个用户可以有多个站点的平面图,每个站点有多个建筑物,每个有多个楼层,每个有多个房间。

它是一个级联的、树状的层次结构。在那里有 onDelete=Cascade 有意义吗?我想是的,但想听听那些更有知识的人的意见

【问题讨论】:

【参考方案1】:

这很大程度上取决于您的具体用例。由于您无论如何都在尝试删除用户,并且您希望它作为清理的一部分自动发生,因此对我来说似乎是使用 ON DELETE 的不错选择。

不过,我可能不会删除这些记录。我将停用它们,将公司设置为非活动状态。然后 ON UPDATE 将是一个很好的候选,它将非活动状态级联到公司的所有用户。

我会犹豫是否要删除,原因有两个:

首先,如果公司返回,这可以让您恢复您想要的部件以便更快地设置。如果公司被错误删除,则不太可能触发从备份恢复。

其次,我假设这些实体也会传播到其他表中。我不想仅仅因为我们不再有活跃的关系就删除客户/供应商的订单历史记录。即使您不从这些其他表中删除记录,您最终也可能会在这些记录中孤立 companyId/userId。

【讨论】:

感谢您的精彩回答 (+1)。我只是使用了一个相关问题中的示例,该问题恰好是关于商业的。我的应用更像是创建了一个组织结构图。或者,想象一下建筑:一个用户可以有多个站点的计划,每个站点有多个建筑物,每个有多个楼层,每个有多个房间。我将更新问题以反映这一点。你现在怎么想?

以上是关于我应该在外键上使用 onDelete=cascade 吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在一对一关系中使用 onDelete: 'CASCADE'

Laravel 迁移:从现有外键中删除 onDelete('cascade')

OnDelete(DeleteBehavior.Cascade) 可能会导致循环或多个级联路径

Laravel 外键 onDelete('cascade') 不起作用

级联=“删除” VS orphanRemoval=true VS ondelete="CASCADE

@OnDelete Hibernate 注解不会为 MySql 生成 ON DELETE CASCADE