防止在Oracle中同时读取行

时间:2016-07-26 14:17:13

标签: oracle

我有一个回调机制,基本上从给定匹配条件的表中获取一行,执行一些操作并基于行记录中的删除标记删除该行。

问题是在此系统中可能存在多个具有相同匹配条件的并发回调。我想要实现的是,在第一个回调中,当我选择要处理的行时(基于删除标记,此行可能会被删除或者在处理后没有删除),我希望其他回调等待。换句话说,我希望在表的行上有一个读锁定,如果在第一个回调中确实删除了它,那么第二个回调就无关紧要了它应该通过。

我在这里使用JDBC来执行这些操作。

2 个答案:

答案 0 :(得分:3)

您可以使用the for update clause锁定您选择的行。尝试检索相同行的第二个会话(也具有for update)将默认阻止,直到您通过提交或回滚来释放锁。

所以会话1确实:

select column1, column2, ... from your_table where ... for update;

并且可以处理结果。虽然它正在进行第2次会议但是:

select column1, column2, ... from your_table where ... for update;

但现在会阻止,直到会话1释放锁。

作为一个简单的演示,让我们有一个小桌子:

create table t42 (id number, delete_flag varchar2(1));
insert into t42 values (1, 'N');
insert into t42 values (2, 'N');
insert into t42 values (3, 'Y');

commit;

在第1节:

SQL> select * from t42 where delete_flag = 'Y' for update;

        ID D
---------- -
         2 Y
         3 Y

在第2节:

SQL> select * from t42 where delete_flag = 'Y' for update;

......就在那里等待。

返回会话1,删除您处理的其中一行:

SQL> delete from t42 where id = 2;

1 row deleted.

第二场会议仍在等待。假设出于某种原因,您只想删除那一行并将另一行留在那里,以便回调事务完成。现在在第1节:

SQL> commit;

Commit complete.

立即会议2现在报告:

        ID D
---------- -
         3 Y

当释放锁时,会重新执行查询,因此它会查看当前提交的数据,而不是提交命令时存在的(锁定)数据。

会话2现在已锁定该行,其他会话仍将被阻止,等待会话提交或回滚。如果会话1删除了它已锁定的两个行,则会话2将看到“没有选择行”并且没有行锁(尽管它仍然会阻止表被删除或截断)。

这不完全是读取锁 - 其他会话仍然可以查询表,包括锁定的行,只要它们没有for update子句。但只要你所有的回调都做同样的事情,他们就应该按你的意愿行事。

答案 1 :(得分:1)

我认为您正在寻找Select For Update Cursor。 第一个读者将阻止其他读者(如果包含NOWAIT子句,则其他会话将不会等待)