我可以使用什么最少侵入性的锁定机制来防止将行插入Oracle表中?

时间:2010-02-17 17:51:11

标签: oracle stored-procedures locking

我定义了父/子关系,遗憾的是,它不能通过外键维护。父母和孩子都存放在同一张桌子上。父/子关系由列“ITEM_ID”标识。子ITEM_ID由其父ITEM_ID组成,然后我们可以有效地将其视为该父项中子项的唯一标识符。

我正在实施一个PL / SQL过程来删除此ITEM表中的记录。程序的第一部分检查是否存在任何子女;如果是这样,它会引发应用程序错误(模拟外键)。

我想知道如何防止在我的删除过程中的光标填充和锁定“FOR UPDATE”之间以及实际删除父记录的时间点之间由另一个进程插入子记录。

在此过程中是否需要锁定整个表格?

或者我应该更改插入程序以选择父记录“FOR UPDATE”?

更新:我创建上面的示例只是为了描述一般情况,但为了证明我的外键/约束问题,我将在下面给出我的实际/更复杂的结构:

远程数据库中有几个表:COMPANY,BUILDING,FLOOR。在我们的组织中,Floors属于建筑物,而建筑物属于公司。

我正在处理的应用程序将角色与员工联系起来。将Employee(员工ID)与角色(角色ID)相关联的表也具有“位置”列。 location列对应于远程数据库表中的一个ID,我们根据Role表中的Type列标识它所属的表。

例如,以下是我桌子上的几条记录:

Role = Janitor
Type = BUILDING
Location = COMPANY1-BUILDING1
Parent Role = Manager


Role = Manager
Type = COMPANY
Location = COMPANY1
Parent Role = CEO

您可以猜到,楼层标识符在远程数据库表中具有公司建筑楼层的格式。

Janitor与BUILDING级别绑定,因此其Location列是BUILDING标识符(实际上是公司标识符,后跟BUILDING表中的建筑物标识符)。

4 个答案:

答案 0 :(得分:4)

让删除过程在父记录上获得普通锁定不会阻止插入子记录。锁定整个表会严重序列化您的应用程序。

因此强制插入进程到父记录的SELECT ... FOR UPDATE以及锁定父记录的删除过程是唯一的选择。这种实现的主要问题是它很容易循环。换句话说,与表交互的每个进程都必须发出这些额外的锁。

答案 1 :(得分:2)

正如APC所提到的,数据模型似乎存在问题。模拟这种层次数据的正确方法是:

key_field            [data_type] primary key
parent_key_field     [data_type] null foreign key references key_field

此处的序列化问题是为什么应该使用foriegn键映射这些关系。

也就是说,如果你打开一个针对你的表的SELECT FOR UPDATE游标,它应该独占锁定你有兴趣删除的行。您无法阻止某人“引用”“外键”中的该表,因为ITEM_ID只是另一个值。

可能有效的是嵌入这个:

procedure delete_me (p_item_key)
as
  l_child_count number;
begin
  -- verify the value being deleted exists and has no children as you already do

  delete from tbl a
   where not exists (select null
                       from tbl b
                      where b.item_id = a.item_id)
  if sql%rowcount = 0 then
    -- your delete failed; raise an error.
  end if;
end;

答案 2 :(得分:1)

如您所说,在插入子项期间,您需要锁定父记录,以便其他用户在您提交之前无法删除父记录。

我很好奇,为什么你说这不能通过外键约束来实现?

答案 3 :(得分:1)

加强APC关于改变每个过程的评论,这是其中一个复杂因素。

  

防止儿童记录被发现   由另一个进程插入   我删除光标的时间   过程填充并锁定“FOR   更新“,以及   父记录实际上已删除。

请记住,当您尝试锁定父记录时,可能已插入(但未提交)子记录。除非插入子记录的过程也取消对父项的独占锁定(防止您的删除获得锁定),否则它将无效。由于一次只有一个事务可以对一行进行独占锁定,因此会序列化插入。

您面临的问题是,通过在父级下序列化插入,还是在删除事务期间锁定整个表,您是否会对应用程序产生更大的影响。如果删除很少并且事务处理很快,我会选择将表锁作为最简单的实现。