外键约束:何时使用ON UPDATE和ON DELETE

时间:2011-07-16 20:30:50

标签: mysql sql database foreign-keys

我正在使用MySQL Workbench设计我的数据库模式,这非常酷,因为你可以做图表并将其转换为:P

无论如何,我决定使用InnoDB,因为它支持外键。我注意到的一件事是,它允许您为外键设置On Update和Delete选项。有人可以解释在一个简单的例子中可以使用“Restrict”,“Cascade”和set null吗?

例如,假设我有user表,其中包含userID。并说我有一个消息表message,它是一个多对多的,有2个外键(在userID表中引用相同的主键user)。在这种情况下,设置On Update和On Delete选项是否有用?如果是这样,我选择哪一个?如果这不是一个好例子,你能否提出一个很好的例子来说明这些如何有用?

由于

3 个答案:

答案 0 :(得分:441)

不要犹豫,在数据库上加上约束。您将确保拥有一致的数据库,这是使用数据库的一个很好的理由。特别是如果您有多个应用程序请求它(或只有一个应用程序,但使用直接模式和使用不同来源的批处理模式)。

使用MySQL,你没有像在postgreSQL中那样的高级约束,但至少外键约束非常先进。

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

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 UPDATE 子句:

  • ON UPDATE RESTRICT 默认:如果您尝试更新表COMPANY中的company_id,如果一个USER至少链接到该公司,则引擎将拒绝该操作。
  • ON UPDATE NO ACTION :与RESTRICT相同。
  • ON UPDATE CASCADE 通常最好的:如果更新一行表中的company_id,引擎会在引用此COMPANY的所有USER行上相应地更新它(但在USER表上没有激活触发器,警告)。引擎会跟踪你的变化,这很好。
  • ON UPDATE SET NULL :如果更新表COMPANY行中的company_id,引擎会将相关的USERs company_id设置为NULL(应该在USER company_id字段中可用)。在更新时我看不出任何有趣的事情,但我可能错了。

现在在 ON DELETE 方面:

  • ON DELETE RESTRICT 默认:如果您尝试删除表COMPANY中的company_id Id,如果一个USER至少链接到该公司,则引擎将拒绝该操作,可以挽救你的生命。
  • ON DELETE NO ACTION :与RESTRICT相同
  • ON DELETE CASCADE dangerous :如果删除表COMPANY中的公司行,引擎将删除相关的USER。这很危险,但可用于在辅助表上进行自动清理(因此它可能是您想要的,但肯定不适用于COMPANY< - > USER示例)
  • ON DELETE SET NULL handful :如果删除COMPANY行,相关的USER将自动与NULL关联。如果Null是您没有公司的用户的价值,那么这可能是一个很好的行为,例如,您可能需要将用户留在您的应用程序中,作为某些内容的作者,但删除公司对您来说不是问题。

通常我的默认值为: ON DELETE RESTRICT ON UPDATE CASCADE 。当主表是包含外键的表的“简单属性”时,某些ON DELETE CASCADE用于跟踪表(日志 - 不是所有日志 - ,类似的东西)和ON DELETE SET NULL USER表的JOB表。

修改

我写这篇文章已经很久了。现在我想我应该添加一个重要警告。 MySQL对级联有一个很大的记录限制。 级联不会触发。因此,如果您对该引擎过于自信以使用触发器,则应该避免级联约束。

  

MySQL触发器仅针对SQL语句对表所做的更改进行激活。它们不会激活视图中的更改,也不会通过不将SQL语句传输到MySQL服务器的API所做的更改来激活

<强> ==&GT;请参阅下面的最后一次修改,此内容正在移动

  

外键操作不会激活触发器。

我不认为有一天会得到修复。外键约束由InnoDb存储管理,触发器由MySQL SQL引擎管理。两者都是分开的。 Innodb是唯一具有约束管理的存储,也许它们有一天会直接在存储引擎中添加触发器,也许不会。

但我对自己应该在糟糕的触发器实现和非常有用的外键约束支持之间选择哪个元素有自己的看法。一旦你习惯了数据库的一致性,你就会喜欢PostgreSQL。

12 / 2017-更新此关于MySQL的编辑:

@IstiaqueAhmed在评论中指出,情况已经发生了变化。因此,请点击链接并查看真实的最新情况(将来可能会再次发生变化)。

答案 1 :(得分:2)

除了@MarkR答案之外 - 有一点需要注意的是,许多带有ORM的PHP框架无法识别或使用高级数据库设置(外键,级联删除,唯一约束),这可能会导致意外行为。

例如,如果使用ORM删除记录,并且DELETE CASCADE将删除相关表中的记录,ORM尝试删除这些相关记录(通常是自动的)将导致错误。

答案 2 :(得分:1)

您需要在应用程序的上下文中考虑这一点。通常,您应该设计一个应用程序,而不是数据库(数据库只是应用程序的一部分)。

考虑您的应用程序应如何响应各种情况。

默认操作是限制(即不允许)操作,这通常是您想要的,因为它可以防止愚蠢的编程错误。但是,在DELETE CASCADE上也很有用。这实际上取决于您的应用程序以及您打算如何删除特定对象。

就个人而言,我会使用InnoDB,因为它不会丢弃你的数据(c.f.MyISAM,它确实如此),而不是因为它有FK约束。

相关问题