数据库 - 在不同记录

时间:2015-07-29 14:15:22

标签: database oracle synchronization sql-update

我有一个像这样的表结构:

ParentObject(ObjectId string,.....)

ChildObject(ObjectId string,ParentId String,Atribute1 String,State Integer ....)

有多个ParentObject记录(接近1000个),每个ParentObject记录表由ChildObject表中的多个记录(接近50个)引用。

我有两个在不同机器上运行的并行进程,它们使用OCI库调用在循环中执行此查询。 UPDATE ChildObject SET Attribute1='<process_name>' WHERE ObjectId = ANY (SELECT TOP 100 ObjectId FROM ChildObject alias1 WHERE State = 0 AND NOT EXISTS (SELECT * FROM ChildObject alias2 WHERE alias2.State = 0 AND alias2.Attribute1 <> ' ' AND alias2.ParentId = alias1.ParentId))

语法可能不完美。逻辑是每个进程在运行中更新100个ChildObject记录,并将Attribute1设置为进程名称(如果尚未设置),休眠一段时间并再次开始更新。

我的要求是,所有引用同一ParentObject记录的ChildObject记录都应该由一个进程更新。例如,如果Process1更新具有相同ParentId的10个ChildObject记录,则具有相同ParentId的其余ChildObject记录应由Process1更新,而不是由Process2更新。

由于进程并行运行,因此一些ChildObject记录在一个进程中更新,一些具有相同ParentId的ChildObject记录在另一个进程中更新。

选择..对于更新在我的情况下不起作用,因为更新发生在ChildObject表中的不同记录上。

锁定整个ChildObject表可能不是一个好的解决方案。

您能否建议我如何实现此同步?

谢谢,

Vanathi

2 个答案:

答案 0 :(得分:0)

如何将ProcessName列添加到ParentObject表中。如果ProcessName为null,则首先要更新子进程的进程必须在父进程上设置ProcessName(在更新查询中包含条件,不要先检查它)。即使两个进程都尝试同时设置父ProcessName,也只有一个进程成功。然后,该进程读取父进程的ProcessName,如果它是自己的名称,则继续更新子进程。

如果您无法添加或修改表格,请将查询更改为:

UPDATE ChildObject
SET Attribute1='<process_name>'
WHERE ObjectId = ANY (
    SELECT TOP 100 ObjectId
    FROM ChildObject alias1
    WHERE State = 0 AND NOT EXISTS (
        SELECT *
        FROM ChildObject alias2
        WHERE alias2.Attribute1 <> ' '
          AND alias2.Attribute1 <> '<process_name>'
          AND alias2.ParentId = alias1.ParentId
    )
)

答案 1 :(得分:0)

只需将父行锁定为第一步。这将阻止任何其他会话(具有相同的锁定机制)处理该行

SELECT *
  FROM ParentObject
 WHERE ObjectID = <<whatever>>
   FOR UPDATE;

UPDATE ChildObject ...

根据Oracle版本以及您正在执行的操作,您可能不希望线程阻止等待无限期锁定ParentObject行。您可能想要执行FOR UPDATE NOWAIT,如果您无法锁定父行,则会捕获异常,然后转到下一行。或者您可能需要FOR UPDATE SKIP LOCKED来确定要处理的下一个ObjectID