首页 > 解决方案 > 当有多个进程并行运行时,只消耗表中的一条记录进行处理

问题描述

假设我有一个批处理表,它存储批处理记录列表。java进程需要从表中选择一条记录(最旧的)进行处理。类似的java进程会在不同的机器上并行运行

用例:第二个流程不应选择与第一个流程相同的记录。

create table batch
(
 id number primary key,
 worker varchar2(32),
 status varchar2(32),
 created date
);


insert into batch values(1, null, null, sysdate);
insert into batch values(2, null, null, sysdate+6);

我正在考虑以下问题

  1. 发出更新命令以使用谓词更新批处理表上的一行 - 状态为空,工作人员为空。
  2. 如果更新计数 > 0,则从表中获取一条记录,其中 worker = 'current worker' 并且状态正在进行中
update batch set worker = 'worker1', status = 'IN_PROGRESS' where
id = (
  select id from (
   select id from batch 
     where status is null and worker is null order by created desc
   ) where rownum = 1
) and status is null and worker is null;
select * from batch where worker = 'worker1' and status = 'IN_PROGRESS'

在这种情况下,当多个java进程发出更新命令时,

  1. 更新语句会是原子的,它会按预期工作吗?
  2. 除了如果工人死亡可能无法处理记录这一事实之外,这种方法是否会有任何问题。

标签: javaoracle

解决方案


每个 Java 程序都需要锁定它已获取的记录,并且还需要跳过任何已被另一个程序锁定的记录。这可以通过 SKIP LOCKED 子句来实现。

因此,您的 Java 程序会打开一个光标,如下所示:

SELECT *
FROM t
FOR UPDATE SKIP LOCKED;

当您获取时,如果您遇到未锁定的行,您将“获取”并锁定它。如果您点击了已经被另一个会话获取(并因此锁定)的行,那么它将不会返回给这个调用程序。


推荐阅读