我有一个分布式应用程序,它使用数据库来同步客户端。客户端将尝试更新记录,但只有在过去1小时内没有其他客户端更新记录时才会这样做。
这是缩小的代码和困境:
假设一个客户端尝试将字段更新为“红色”(检查过去一小时内没有其他人更新过该字段):
UPDATE mytesttable
SET Status = 'Red',
TimeOfLastUpdate = sysdate
WHERE TimeOfLastUpdate < sysdate-1/24
同时,另一个客户端尝试将其更新为“绿色”(检查过去一小时内没有其他人更新过它):
UPDATE mytesttable
SET Status = 'Green',
TimeOfLastUpdate = sysdate
WHERE TimeOfLastUpdate < sysdate-1/24
我可以假设只有一个客户端才能成功更新行吗?
这就是我认为答案是“不”的原因:
由于Oracle必须在之前解析sysdate
,它才会获取行级更新锁(因为它必须首先使用它来查找行),所以看起来有一场比赛条件:
sysdate
sysdate
TimeOfLastUpdate
sysdate
TimeOfLastUpdate
更新sysdate
(因此会更新两次)我认为这是一种竞争条件吗?如果没有,我错过了什么?
如果是这样,是否有一个有效,更可靠的解决方案来解决这个问题?
答案 0 :(得分:0)
根据我的理解,这些场景应该在代码级别处理,而不是留在后端。在编程期间可以轻松处理同步。尝试以这种方式实现。
答案 1 :(得分:0)
对我有用的解决方案:加倍update
。例如:
UPDATE mytesttable
SET TimeOfLastUpdate = TimeOfLastUpdate
WHERE TimeOfLastUpdate < sysdate-1/24
UPDATE mytesttable
SET Status = 'Red',
TimeOfLastUpdate = sysdate
WHERE TimeOfLastUpdate < sysdate-1/24
COMMIT;
('Green'的类似代码)
第一个update
不会改变任何内容,但会抓住该行的锁定,直到调用commit
才会释放。
第二次更新使用sysdate
更新行,该行保证大于或等于获取锁定的时间,从而防止竞争条件。 (除非sysdate
及时倒退。)