初步情况:
我在事务中向CHILD_TABLE1插入一行,但不提交。
然后我尝试在另一个会话中创建一个与CHILD_TABLE1对称的CHILD_TABLE2表。
但是当我创建外键时会引发ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
,因为CHILD_TABLE1中正在插入。
我不明白为什么Oracle会阻止外键创建:PARENT_TABLE没有修改。
请帮忙。
在sqlplus下重现:
set autocommit off
create table PARENT_TABLE(PK_COL varchar(10));
alter table PARENT_TABLE add constraint PK_CONSTRAINT primary key (PK_COL);
insert into PARENT_TABLE values ('foo');
commit;
create table CHILD_TABLE1(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE1 add constraint CHILD_TABLE1_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
create index CHILD_TABLE1_INDEX on CHILD_TABLE1(FK_COL);
insert into CHILD_TABLE1 values ('bar', 'foo');
在另一个控制台中:
alter session set ddl_lock_timeout=10;
create table CHILD_TABLE2(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE2 add constraint CHILD_TABLE2_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
搞笑:在CHILD_TABLE2_CONSTRAINT创建中使用NOVALIDATE,执行挂起......
答案 0 :(得分:2)
您没有修改父表中的内容。但是你呢 实际上,尝试在子表中引用其主键。之前 与表建立关系或任何
DDL
,它必须是免费的 锁。
因此,在创建此约束之前,Oracle会检查引用表(PARENT_TABLE
)上的现有锁定。锁定表(在此上下文中为表级锁定)实际上是为了遵守ACID
属性。
了解其重要性的一个最佳示例是ON DELETE CASCADE
,这意味着如果父表中的记录被删除,则子表中的相应记录将被自动删除。
因此,当引用父表时,子表上存在未提交的插入/更新/删除。不能为父级创建其他参照约束。只是为了避免陷入僵局或混乱。
当您的子表中有未提交的插入时,要更加清晰。 您的父表也会锁定。所以所有其他引用它的DDL都会等待。
您可以使用此查询来检查相同内容。
SELECT c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
FROM v$locked_object a ,
v$session b,
dba_objects c
WHERE b.sid = a.session_id
AND a.object_id = c.object_id;
答案 1 :(得分:0)
我在你的查询中添加了LOCKED_MODE解释:
DECODE(a.LOCKED_MODE, 0,'NONE', 1,'NULL', 2,'ROW SHARE (RS/SS)', 3,'ROW EXCLUSIVE (RX/SX)', 4,'SHARE (S)', 5,'SHARE ROW EXCLUSIVE (SRX/SSX)', 6,'EXCLUSIVE (X)', NULL) LOCK_MODE.
结果如下:
OBJECT_NAME OBJECT_TYPE LOCK_MODE SID SERIAL# STATUS
------------------------------ ------------------- ----------------------------- ---------- ---------- --------
PARENT_TABLE TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
CHILD_TABLE1 TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
RX / SX是一个表锁,因此它可以防止任何DDL操作(这似乎在doc中说过)。此锁用于父和子。我想在父级上添加了锁,至少可以防止它被删除,所以我们会丢失子表上的挂起更新。
那就是说,我仍然没有解决方案。假设父表是制造商。有一个儿童汽车表,我们正在动态插入大量新车。从汽车到制造商有一个外键。现在有一种我们想要管理的新产品:“自行车”。因此,我们要创建一个类似于 car 的自行车表。但是我们无法创建表格,因为我们在 car 中执行插入操作。似乎是一个非常简单的用例...如何支持它?
===== 编辑: 可能没有解决方案。 Here is a guy with the same issue