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

mel*_*amy 181 mysql sql database foreign-keys

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

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

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

谢谢

reg*_*ero 463

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

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

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

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;
Run Code Online (Sandbox Code Playgroud)

我们来看看ON UPDATE子句:

  • ON UPDATE RESTRICT:默认值:如果您尝试更新表COMPANY中的company_id,如果一个USER至少链接到该公司,则引擎将拒绝该操作.
  • ON UPDATE NO ACTION:与RESTRICT相同.
  • ON UPDATE CASCADE:通常是最好的一个:如果你更新一行表COMPANY中的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:危险:如果删除表COMPANY中的公司行,引擎将删除相关的USER.这很危险,但可用于在辅助表上进行自动清理(因此它可能是您想要的,但肯定不适用于COMPANY < - > USER示例)
  • ON DELETE SET NULL:少数:如果删除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所做的表

==>请参阅下面的最后一次编辑,这个域名正在发生变化

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

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

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

12/2017 - 更新此编辑MySQL:

正如@IstiaqueAhmed在评论中所说,情况已经发生了变化.因此,请点击链接并检查真实的最新情况(将来可能会再次发生变化).

  • `ON DELETE CASCADE:危险' - 带上一小撮盐. (8认同)
  • _“我不希望客户删除以清除其先前拥有的订单的财务数据。” _在这种情况下,您可能仍然仍然需要客户的数据。您的设计可能应该将客户标记为不活动,而不是从数据库中删除他们的行。实际上,根据我的专业经验,您实际上_非常_很少想要删除_anything_,而是默认情况下标记为不活动。在永久删除_is_ ok的情况下,通常也可以执行“ CASCADE DELETE”,甚至是首选。我认为这不是特别危险。 (4认同)
  • 您需要注意级联,如果需要更改大量记录,它可能会锁定您的系统.在使用之前应特别仔细查看Cascde删除,通常你真的希望如果有子记录就不会发生删除.我不希望客户删除,以消除他以前的矿工的财务数据.有时最好确保cacading没有打开,并提供amrk记录为非活动状态的方法. (3认同)
  • 就业务逻辑而言,有一种情况可能对“ON UPDATE”中的“SET NULL”感兴趣:更新公司代表公司&gt;用户关系的分离。例如:如果一家公司改变了其业务类型,以前的用户可能不再与该业务相关,因此“NULL”可能更适合该索引。 (2认同)