1

我有一个分布式应用程序,它使用数据库来同步客户端。客户端将尝试更新记录,但只有在过去 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 之前解决(因为它必须首先使用它来查找行),所以似乎存在竞争条件:

  1. 客户端“红色”计算sysdate
  2. 客户“Green”计算sysdate
  3. 1小时通行证
  4. 客户端“红色”更新TimeOfLastUpdate为旧sysdate
  5. 客户端“绿色”更新TimeOfLastUpdatesysdate(因此更新两次)

我将其确定为比赛条件是否正确?如果没有,我错过了什么?

如果是这样,是否有有效、更可靠的解决方案来解决这个问题?

4

2 回答 2

0

根据我的理解,这些场景应该在代码级别处理,而不是留给后端。在编程期间可以轻松处理同步。尝试以这种方式实施。

于 2013-04-17T13:53:07.967 回答
0

对我有用的解决方案: double update。例如:

UPDATE mytesttable
SET TimeOfLastUpdate = TimeOfLastUpdate 
WHERE TimeOfLastUpdate < sysdate-1/24

UPDATE mytesttable
SET Status = 'Red',
    TimeOfLastUpdate = sysdate 
WHERE TimeOfLastUpdate < sysdate-1/24

COMMIT;

(“绿色”的类似代码)

第一个update不会改变任何东西,但它会抓住行上的锁,直到commit被调用才会释放。

sysdate第二次更新使用保证大于或等于获取锁的时间的a 更新行,从而防止竞争条件。(除非sysdate时光倒流。)

于 2013-04-29T14:20:10.993 回答