Oracle锁定问题 - ORA-00054:资源繁忙 - 创建外键时

时间:2015-08-06 16:17:19

标签: oracle locking

初步情况:

  • 一个PARENT_TABLE表,其PK_COL列上有一个主键。
  • 在PARENT_TABLE(PK_COL)上使用外键的表CHILD_TABLE1。

我在事务中向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,执行挂起......

2 个答案:

答案 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