代码之家  ›  专栏  ›  技术社区  ›  druid1123

当有多个进程并行运行时,只使用表中的一条记录进行处理

  •  0
  • druid1123  · 技术社区  · 5 年前

    假设我有一个批处理表,其中存储了批处理记录的列表。 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. 发出update命令以使用更新批处理表上的一行 谓词-状态为null,工作者为null。
    2. 如果更新了计数>0,从worker='current worker'且状态为progress的表中获取一条记录
    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. update语句是原子的吗?它会按预期工作吗?
    2. 除了如果员工死亡,记录可能无法处理之外,这种方法还会有任何问题吗。
    0 回复  |  直到 5 年前
        1
  •  3
  •   Connor McDonald    5 年前

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

    因此,您的Java程序会沿着以下几行打开一个光标:

    SELECT *
    FROM t
    FOR UPDATE SKIP LOCKED;
    

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

        2
  •  1
  •   yeahseol    5 年前
    1. update语句是原子的吗?它会按预期工作吗?

    对但这太复杂了。

    update batch set worker = 'worker1', status = 'IN_PROGRESS' where status is null and worker is null;
    

    数据库保证此sql的并发性。
    但我建议使用MQ(消息队列)。
    这是因为大量线程或进程会降低性能并导致死锁。
    参考拉比和卡夫卡。

    1. 除了如果员工死亡,记录可能无法处理之外,这种方法还会有任何问题吗。

    对如果工作进程在处理过程中死亡,消息将保留在数据库中,不被引用。 你必须自己更新这些记录。

    出于队列目的使用数据库不是一个好主意。
    确保使用MQ。