我有一个这样的表结构:
ParentObject(ObjectId字符串,.....)
ChildObject(ObjectId字符串,ParentId字符串,Attribute1字符串,State字符串.)
有多个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更新了10条具有相同ParentId的ChildObject记录,则ChildObject中具有相同ParentId的其余记录应由Process1而不是Process2更新。
由于进程并行运行,因此在一个进程中更新某些ChildObject记录,而在另一个进程中更新具有相同ParentId的某些ChildObject记录。
Select.. For Update在我的情况下不起作用,因为更新发生在ChildObject表中的不同记录上。
锁定整个ChildObject表可能不是一个好的解决方案。
你能告诉我如何实现这种同步吗?
谢谢你,
瓦纳蒂
3条答案
按热度按时间p5cysglq1#
如何将ProcessName列添加到ParentObject表中。如果ProcessName为空,则希望首先更新子进程的进程必须在父进程上设置ProcessName(在更新查询中包含该条件,之前不要检查它)。即使两个进程同时尝试设置父进程名,也只有一个进程会成功。然后进程读取父进程的ProcessName,如果是自己的名字,则继续更新子进程。
如果您无法添加或修改表,那么将查询更改为:
scyqe7ek2#
第一步只需锁定父行。这将阻止任何其他会话(具有相同的锁定机制)处理该行
根据Oracle版本和您正在做的事情,您可能不希望线程阻塞等待无限期地锁定
ParentObject
行。您可能希望执行FOR UPDATE NOWAIT
,如果无法锁定父行,则捕获异常,然后继续下一行。或者您可能希望执行FOR UPDATE SKIP LOCKED
以确定要处理的下一个ObjectID
。hrysbysz3#
我们遇到了类似的问题,多个k8s pod在update query下并行执行,并陷入死锁
因此,我们需要锁定会话1将要更新的行集,这将阻止其他会话更新相同的行。
带有FOR UPDATE的选择查询将锁定这些行集,并且只有在提交或回滚后才释放锁定
并且FOR UPDATE SKIP LOCKED将锁定下一组行,而不是等待第一个会话释放锁定