数据库中是否可接受循环引用?

时间:2009-06-17 13:13:24

标签: database oracle circular-dependency

数据库中何时可接受循环引用?

理论和实践,感谢任何帮助。

8 个答案:

答案 0 :(得分:23)

考虑城市和州。每个城市都在一个州内。每个州都有一个首都。

CREATE TABLE city (
  city  VARCHAR(32),
  state VARCHAR(32),
  PRIMARY KEY (city),
  FOREIGN KEY (state) REFERENCES state (state)
);

CREATE TABLE state (
  state VARCHAR(32),
  captial_city VARCHAR(32),
  PRIMARY KEY (state),
  FOREIGN KEY (captial_city) REFERENCES city (city)
);

第一个问题 - 您无法如图所示创建这些表。解决方案是在没有外键的情况下创建它们,然后再添加外键。

第二个问题 - 您无法在任何一个表中插入行,因为每个插入都需要另一个表中预先存在的行。解决方案是将其中一个外键列设置为NULL,并将该数据分两个阶段插入。 e.g。

INSERT INTO city (city, state) VALUES ('Miami', NULL);
INSERT INTO state (state, capital_city) VALUES ('Florida', 'Miami');
UPDATE city SET state='Florida' WHERE city='Miami';

答案 1 :(得分:13)

指向其他记录的记录在数据库中很有用。有时这些记录形成一个循环。这可能仍然有用。实践中唯一真正的烦恼就是避免违反约束条件。

例如,如果您有用户和事务表,则该用户可能具有指向其上一个事务的指针。您需要先插入事务,然后将last_transaction_id更新为正确的值。虽然这两个记录都存在但您无法删除它们,因为user.last_transaction_id指向transaction.idtransaction.user_id指向user.id。这意味着没有事务的用户具有空last_transaction_id。这也意味着您必须先删除该字段,然后才能删除该事务。

管理这些外键约束是一种痛苦,但肯定是可能的。如果稍后向数据库添加约束会引入新的循环依赖关系,则可能会出现问题。在这种情况下你必须要小心。但是,只要循环中的一个记录具有可空的外键字段,就可以中断循环并删除记录。只要您按正确的顺序插入记录,更新通常不会成为问题。

答案 2 :(得分:4)

Oracle层次查询语法的最新成员之一 - NOCYCLE关键字 - 是出于明确的目的 - 处理数据中的循环引用。我没有看到它有任何问题,并且之前不得不处理这种模型。这并不困难,特别是在支持可延迟约束的Oracle中。

答案 3 :(得分:3)

技术上可行,但在删除记录时会产生各种问题,因为它会产生鸡蛋问题。这些问题通常会采取激烈的行动,例如手动删除FK并删除要解决的违规项目。

如果你有这样的关系:

create table foo_master (
       foo_master_id int not null primary key
      ,current_foo_id int
)


create table foo_detail (
       foo_detail_id int not null primary key
       foo_master_id int not null
)

alter table foo_master
  add constraint fk_foo_current_detail
      foreign key (current_foo_id)
      references foo_detail

alter table foo_detail
  add constraint fk_foo_master
      foreign key (foo_master_id)
      references foo_master

然后,由于循环依赖性,删除记录会导致这样的鸡和焦点问题。

更好的架构如下所示:

create table foo_master (
       foo_master_id int not null primary key
)


create table foo_detail (
       foo_detail_id int not null primary key
       foo_master_id int not null
       is_current char (1)
)

alter table foo_detail
  add constraint fk_foo_master
      foreign key (foo_master_id)
      references foo_master

这意味着该关系是非循环的,并且仍然可以识别“当前”foo_detail记录。

答案 4 :(得分:1)

应像瘟疫一样避免循环引用。可以设置双向关系,甚至可以建立与自己的关系(如果你是一个表),但循环依赖只是要求麻烦。

答案 5 :(得分:1)

我已经看到因性能原因而完成的循环引用。虽然它看起来很丑陋,但性能可能微乎其微。

示例:一些公告牌(我认为phpBB这样做)在类别表中有一个lastpostid,它是线程中最后一篇文章的快捷方式。

这会创建一个圆圈,其中最后一个帖子对类别表有一个FK,而类别表有一个FK回到最后一个帖子。

就像我说的那样,我并不喜欢它,但我已经看过它了。

答案 6 :(得分:0)

我很少遇到必要的1:1关系并且建立了循环关系

请注意,此类关系中的外键字段必须是可空的,否则您永远不能从表中删除行

答案 7 :(得分:0)

如果您使用的是只写数据库,我想这不是问题。如果你计划使用CRUD的RUD部分,你可能会遇到(通常是可以避免的)复杂问题。