2013-04-16 15 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服務器會引入大量未來的維護。 –