外键约束中的mysql循环依赖

时间:2012-09-29 11:03:26

标签: mysql sql database-design referential-integrity

鉴于架构:

enter image description here

我需要的是每个user_identities.belongs_to引用users.id

同时,每张users都有primary_identity,如图所示。

但是,当我尝试使用ON DELETE NO ACTION ON UPDATE NO ACTION添加此引用时,MySQL说

  

#1452 - 无法添加或更新子行:外键约束失败(yap#sql-a3b_1bf,CONSTRAINT #sql-a3b_1bf_ibfk_1 FOREIGN KEY(belongs_to)REFERENCES {{ 1}}(users)ON DELETE NO ACTION ON UPDATE NO ACTION)

我怀疑这是由于循环依赖,但我怎么能解决它(维护参照完整性)?

6 个答案:

答案 0 :(得分:7)

解决此问题的唯一方法(至少使用MySQL的有限功能)在两个FK列中允许NULL值。创建具有主要标识的新用户将看起来像这样:

insert into users (id, primary_identity)
values (1, null);

insert into identities (id, name, belongs_to)
values (1, 'foobar', 1);

update users 
  set primary_identity = 1
where id = 1;

commit;

此解决方案的唯一缺点是您不能强制用户具有主要身份(因为该列需要可以为空)。


另一个选择是更改为支持延迟约束的DBMS,然后您可以只插入两行,并且仅在提交时检查约束。或者使用DBMS,您可以在其中获得部分索引,然后您可以使用is_primary列的解决方案

答案 1 :(得分:6)

我不会这样实现它。

从表格primary_identity中移除字段users,然后在名为user_profiles的表格is_primary中添加其他字段,并将其用作主要配置文件的指标

答案 2 :(得分:1)

这将阻止FKs使用NULL,但仍然不强制主要配置文件存在 - 必须由应用程序管理。

请注意{UserID, ProfileID}表上的备用键(唯一索引)Profile,并在PrimaryProfile上匹配FK。

enter image description here

答案 3 :(得分:1)

这个问题是在How to drop tables with cyclic foreign keys in MySQL从删除方面提出的,但我认为其中一个答案也适用于此:

SET foreign_key_checks = 0;
INSERT <user>
INSERT <user identity>
SET foreign_key_checks = 1;

将其作为一个事务并立即提交。我没有尝试过,但它适用于删除,所以我不知道为什么它不适用于插入。

答案 4 :(得分:0)

我没有用它,但你可以试试INSERT IGNORE。我会做其中的两个,每个表一个,这样一旦完成,参考完整性就会维持。如果您在事务中执行它们,则可以在插入第二个事件时回滚。

由于您忽略了使用此功能的约束,您应该检查程序代码,否则您可能会在数据库中找到忽略约束的数据。 < / p>

感谢@Mihai指出上述问题。另一种方法是在插入时禁用约束,然后重新启用它们。但是,在可能产生比可接受的更多开销的大型表上 - 尝试一下吗?

答案 5 :(得分:0)

问题似乎是您尝试将主要身份信息保留在user_identities表中。

相反,我建议您将主要用户信息(名称/电子邮件)放入users表中。不要使用user_identities表的外键。

只有来自user_identities表的外键

所有约束现在都可以正常工作,因为它们只是一种方式。

除非主要用户(在表用户中)存在,否则无法输入user_identities。同样,在存在子身份的情况下(在user_identities中),主要用户不应该是可删除的。

您可能希望将表的名称更改为“primary_users”和“secondary_users”,以使其显而易见。

这听起来不错吗?