阻止插入用于更新

时间:2015-04-09 18:40:12

标签: sql oracle locking

我试图阻止在oracle中使用select for update进行插入。例如,假设在一个会话中(自动提交关闭,隔离级别=可序列化),地址表不包含任何行,我在SESSION1中执行:

SESSION1: select * from Address where addressID = 1 for update

现在在SESSION2:

SESSION2:insert into Address (addressID, street, city,zip) values (1, 'main','ny','12345'); commit;

我原本以为被封锁了。但是,我发现插入发生了。我能够承诺。然后再次在SESSION1。

  SESSION1: insert into Address (addressID, street, city,zip) values (1, 'main','ny','12345')

即使在提交之前,这也会产生完整性约束错误。 (不像我预期的那样可序列化的例外)。

为什么会这样?我正在使用oracle 12c。有一些意想不到的结果。首先,为什么我甚至在提交之前在Session1中遇到约束错误? Oracle不应该看到来自其他Session的插入。其次,不应该因为“for update”选择而阻止Session1中的插入?最后,有没有办法阻止特定键的插入?

1 个答案:

答案 0 :(得分:2)

请参阅http://www.oracle.com/technetwork/issue-archive/2010/10-jan/o65asktom-082389.html关于SERIALIZABLE隔离级别。

  

这种程度的隔离带有价格,而且价格就是这个价格   以下可能的错误:

ERROR at line 1: ORA-08177: can't serialize access for this transaction
     

每当您尝试更新具有的行时,您都会收到此消息   您的交易开始后已更改。 (注意Oracle尝试这样做   这纯粹在行级别,但您可能会收到ORA-08177错误   即使您对修改感兴趣的行没有被修改。   ORA-08177可能由于某些其他行被修改而发生   包含行的块。)

在你的情况下,它不是完全更新,但想法是一样的。如果你查询表格,它将不会"见"它因为它从回滚段读取。  但插入是不同的,因为它需要访问真实数据以确保一致性。

至于如何解决它 - 使用命名锁。他们仍然有效,尽管他们不应该:)

Alter session set isolation_level=serializable; 

declare
  v_lockhandle varchar2(128);
  v_result number;
begin
  dbms_lock.allocate_unique('table_name'||'id'
                           ,v_lockhandle);

  v_result := dbms_lock.request(v_lockhandle
                               ,release_on_commit => true
                               ,lockmode => 6 -- exclusive
                               ,timeout => 0);

  dbms_output.put_line('result: '||v_result);
end;
/