我经常使用ON DELETE CASCADE,但我从不使用ON UPDATE CASCADE,因为我不确定在什么情况下它会有用。

为了便于讨论,让我们看一些代码。

CREATE TABLE parent (
    id INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
);

CREATE TABLE child (
    id INT NOT NULL AUTO_INCREMENT, parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(id)
        ON DELETE CASCADE
);

对于ON DELETE CASCADE,如果删除带有id的父级,则child中的记录parent_id = parent。Id将被自动删除。这应该没有问题。

This means that ON UPDATE CASCADE will do the same thing when id of the parent is updated? If (1) is true, it means that there is no need to use ON UPDATE CASCADE if parent.id is not updatable (or will never be updated) like when it is AUTO_INCREMENT or always set to be TIMESTAMP. Is that right? If (2) is not true, in what other kind of situation should we use ON UPDATE CASCADE? What if I (for some reason) update the child.parent_id to be something not existing, will it then be automatically deleted?

好吧,我知道,上面的一些问题可以通过编程测试来理解,但我也想知道这其中是否有依赖于数据库供应商的。

请照点光。


当前回答

是的,这意味着,例如,如果你执行UPDATE parent SET id = 20 WHERE id = 10,所有parent_id为10的子节点也将被更新为20 如果您不更新外键引用的字段,则不需要此设置 我想不出还有什么别的用途。 你不能这样做,因为外键约束会失效。

其他回答

确实,如果你的主键只是一个自动递增的标识值,你就不会真正使用ON UPDATE CASCADE。

但是,假设您的主键是一个10位的UPC条形码,由于扩展,您需要将其更改为一个13位的UPC条形码。在这种情况下,ON UPDATE CASCADE将允许您更改主键值,并且任何具有外键引用的表将相应地更改该值。

参考#4,如果您将子ID更改为父表中不存在的内容(并且具有引用完整性),则应该会得到外键错误。

为了补充其他精彩的答案,在这里谨慎使用ON UPDATE CASCADE(或ON DELETE CASCADE…)是很重要的。对具有此规范的表的操作需要对底层关系进行排他锁定。

如果在一个表中有多个CASCADE定义(如其他答案),特别是多个表使用相同的定义,多个用户更新,当一个进程在第一个底层表上获得排他锁,在第二个底层表上获得其他排他锁,并且由于没有一个进程能够获得两个(所有)排他锁来执行操作而相互阻塞时,就会产生死锁。

是的,这意味着,例如,如果你执行UPDATE parent SET id = 20 WHERE id = 10,所有parent_id为10的子节点也将被更新为20 如果您不更新外键引用的字段,则不需要此设置 我想不出还有什么别的用途。 你不能这样做,因为外键约束会失效。

我认为你已经抓住了要点!

如果您遵循数据库设计最佳实践,并且您的主键永远不可更新(我认为无论如何都应该是这种情况),那么您永远不需要ON UPDATE CASCADE子句。

Zed提出了一个很好的观点,如果你使用一个自然键(例如数据库表中的一个常规字段)作为你的主键,那么在某些情况下你可能需要更新你的主键。另一个最近的例子是ISBN(国际标准书号),不久前它从10位数字+字符变成了13位。

如果你选择使用代理键(例如,人工系统生成的)作为你的主键(在大多数情况下,这是我的首选),情况就不是这样了。

所以最后:如果你的主键从未改变,那么你就永远不需要ON UPDATE CASCADE子句。

Marc

几天前,我遇到了一个触发器问题,我发现ON UPDATE CASCADE可以很有用。看一下这个例子(PostgreSQL):

CREATE TABLE club
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE band
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE concert
(
    key SERIAL PRIMARY KEY,
    club_name TEXT REFERENCES club(name) ON UPDATE CASCADE,
    band_name TEXT REFERENCES band(name) ON UPDATE CASCADE,
    concert_date DATE
);

在我的问题中,我必须定义一些额外的操作(触发器)来更新音乐会的表。这些操作需要修改“club_name”和“band_name”。因为参考问题,我没能做这件事。我不能修改音乐会,然后处理俱乐部和乐队的桌子。我不能用另一种方法来做。ON UPDATE级联是解决这个问题的关键。