外键约束:何时使用ON UPDATE和ON DELETE
我正在使用MySQL Workbench来devise我的数据库模式,这很酷,因为你可以做图表并转换它们:P
无论如何,我决定使用InnoDB,因为它的外键支持。 我注意到的一件事是,它允许您设置“更新”和“删除外键选项”。 有人可以解释一下,“Restrict”,“Cascade”和set null可以用在一个简单的例子中吗?
例如,说我有一个user
表,其中包括一个userID
。 并说我有一个消息表message
,这是一个多对多的有两个外键(引用相同的主键,在user
表userID
)。 在这种情况下设置“更新”和“删除”选项有用吗? 如果是这样,我select哪一个? 如果这不是一个好的例子,请你拿出一个很好的例子来说明这些可能有用吗?
谢谢
不要犹豫,把限制在数据库上。 你一定会有一个一致的数据库,这是使用数据库的好理由之一。 特别是如果您有多个应用程序请求(或者只有一个应用程序,但使用直接模式和使用不同来源的批处理模式)。
使用MySQL,您不像postgreSQL那样拥有高级约束,但至less外键约束相当先进。
我们举一个例子,一个公司的用户表,里面包含了来自公司的人
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至less链接到该公司。
- 在更新没有行动 :一样RESTRICT。
- ON UPDATE CASCADE : 通常最好的一个 :如果你在表COMPANY的一行中更新一个company_id,那么引擎会在所有引用这个COMPANY的USER行上相应地更新它(但是没有在USER表上激活触发器,警告)。 引擎会跟踪你的变化,这是很好的。
- ON UPDATE SET NULL :如果更新表COMPANY一行中的company_id,则引擎将相关用户company_id设置为NULL(应在USER company_id字段中可用)。 在更新上我看不到有什么有趣的事情,但我可能是错的。
现在在ON DELETE方面:
- ON DELETE RESTRICT : 缺省值 :如果您尝试删除表COMPANY中的company_id Id,那么如果一个USER至less链接到该公司,引擎将拒绝该操作,可以挽救您的生命。
- ON DELETE NO ACTION :与RESTRICT相同
- ON DELETE CASCADE : 危险 :如果删除表COMPANY中的公司行,则引擎将删除相关的用户。 这是危险的,但是可以用来在辅助表上进行自动清理(所以它可以是你想要的东西,但肯定不适用于COMPANY < – > USER例子)
- ON DELETE SET NULL : less数 :如果删除COMPANY行,相关的用户将自动将关系设置为NULL。 如果Null对于没有公司的用户是有价值的,那么这可能是一个好的行为,例如,可能需要将用户留在应用程序中,作为某些内容的作者,但是移除公司对您来说不是问题。
通常我的默认值是: ON DELETE RESTRICT ON UPDATE CASCADE 。 有一些ON DELETE CASCADE
用于跟踪表(日志 – 不是所有日志 – 类似的东西), ON DELETE SET NULL
当主表是包含外键的表的“简单属性”时,如JOB表USER表。
编辑
自写这篇文章已经很长时间了。 现在我想我应该加一个重要的警告。 MySQL对级联有一个大的logging限制。 小瀑布不触发触发器 。 所以如果你对这个引擎有足够的信心来使用触发器,你应该避免级联限制。
MySQL触发器仅激活SQL语句对表进行的更改。 它们不会激活视图中的更改,也不会更改由不将SQL语句传送到MySQL服务器的API所做的表
触发器不被外键操作激活。
而且我不认为这一天会得到修复。 外键约束由InnoDb存储pipe理,触发器由MySQL SQL引擎pipe理。 两者是分开的。 Innodb是唯一具有约束pipe理function的存储,也许他们有一天会直接在存储引擎中添加触发器,也许不会。
但我有自己的意见,你应该select差的触发器实现和非常有用的外键约束支持之间的元素。 一旦你习惯了数据库的一致性,你会爱上PostgreSQL。
您需要在应用程序的上下文中考虑这一点。 一般来说,你应该devise一个应用程序,而不是数据库(数据库仅仅是应用程序的一部分)。
考虑你的应用程序应该如何回应各种情况。
默认的操作是限制(即不允许)的操作,这通常是你想要的,因为它可以防止愚蠢的编程错误。 但是,在DELETE CASCADE上也可以有用。 这真的取决于你的应用程序,以及你打算如何删除特定的对象。
就个人而言,我会使用InnoDB,因为它不会垃圾你的数据(比较MyISAM,而不是),而不是因为它有FK的限制。
除了@MarkR的答案 – 有一点要注意的是,许多带有ORM的PHP框架不能识别或使用高级数据库设置(外键,级联删除,唯一约束),这可能会导致意外的行为。
例如,如果使用ORM删除logging,并且DELETE CASCADE
将删除相关表中的logging,则ORM尝试删除这些相关logging(通常是自动)将导致错误。