我试图阻止在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中的插入?最后,有没有办法阻止特定键的插入?
答案 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;
/