2013-04-16 47 views
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名),它似乎有一个竞争条件:

  1. 客户端“红”计算sysdate
  2. 客户“绿色”计算sysdate
  3. 1小时传递
  4. 客户端 “红” 的更新TimeOfLastUpdate与旧sysdate
  5. 客户端的 “绿色” 与旧sysdate更新TimeOfLastUpdate(由此更新两次)

我是正确识别此作为竞赛条件?如果不是,我错过了什么?

如果是这样,是否有一个有效的,更可靠的解决这个问题?

+1

虽然不完全是你的问题,但我认为接受的答案也是我对你的建议。如果您绝对必须确保只有一个人更新它,请使用序列。 http://stackoverflow.com/questions/8498169/race-condition-between-select-and-update –

回答

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; 

(“绿色”类似的代码)

第一update不会改变任何东西,但它抓住该行,这将不会被释放,直到commit的锁被称为。

第二次更新使用sysdate更新行,该行保证大于或等于获取锁定的时间,从而避免竞争条件。 (除非sysdate要及时倒退。)

0

根据我的理解,应该在代码级别处理这些类型的场景,而不是将其留在后端。编程期间可以很容易地处理同步。尝试执行这种方式。

+0

你会如何建议完成此?我不明白它会如何“轻松”处理。请记住,这是一个分布式应用程序,这意味着有多个客户端,它们的时钟不一定是同步的。 –

+0

你是绝对正确的,在这样的分布式应用环境中处理起来并不容易。她的思想是什么,让更新到数据库级别的这种同步不会比编程级别更有效。应该有一些中间接口订阅不同的客户端并进行同步。 – Joshi

+0

这听起来像你建议我创建一个所有客户指向的Web服务。仅为此维护Web服务器会引入大量未来的维护。 –