2010-01-21 89 views
1

我在C API中使用mySQL,但這不應該是相關的。 我的代碼必須處理符合某些條件的表中的記錄,然後更新所述記錄以將它們標記爲處理完畢。表中的行被我不控制的另一個進程修改/插入/刪除。我在下面很害怕,更新可能標誌的一些記錄錯誤,因爲該集記錄匹配的可能步驟1和步驟3SQL(mySQL)更新某個select所處理的所有記錄中的某些值

SELECT * FROM myTable WHERE <CONDITION>; # step 1 
<iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1 WHERE <CONDITION> # step 3 

什麼是聰明的方式,以確保之間已經改變了update更新所有的行處理,只有他們?交易似乎不符合該法案,因爲它沒有提供這種隔離:最近修改的記錄不在最初選擇的集合中,可能仍然是UPDATE語句的目標。出於同樣的原因,SELECT ... FOR UPDATE似乎沒有幫助,但它聽起來很有前途:-)

我能看到的唯一方法是使用臨時表來記憶要處理的行集,做類似的事情:

CREATE TEMPORARY TABLE workOrder (jobId INT(11)); 
INSERT INTO workOrder SELECT myID as jobId FROM myTable WHERE <CONDITION>; 
SELECT * FROM myTable WHERE myID IN (SELECT * FROM workOrder); 
<iterate over the selected set of lines. This may take some time.> 
UPDATE myTable SET processed=1 WHERE myID IN (SELECT * FROM workOrder); 
DROP TABLE workOrder; 

但是這看起來很浪費,效率也不是很高。

有什麼更聰明的嗎?

非常感謝來自SQL新手。

回答

1

我最終被使用,根據他們的狀態標誌線表中列解決了這個問題。這一欄讓我來實現一個簡單的狀態機。從概念上講,我有兩個可能的值此狀態:不

kNoProcessingPlanned = 0; #default "idle" value 
kProcessingUnderWay = 1; 

現在我的算法是這樣的:

UPDATE myTable SET status=kProcessingUnderWay WHERE <CONDITION>; # step 0 

SELECT * FROM myTable WHERE status=kProcessingUnderWay; # step 1 
    <iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1, status=kNoProcessingPlanned WHERE status=kProcessingUnderWay # step 3 

有幾個州行的這種想法可以擴展到更多國家需要

1

有幾種選擇:

  1. 你可以鎖定表

  2. 您可以添加一個與foo_id IN(all_the_ids_you_processed)爲更新條件。

  3. ,你可以選擇之前更新,然後只選擇更新的行(即通過處理日期)

+0

1-鎖定表格意味着阻止另一個進程在我正在處理時工作。它不會很高興... 2-沒有臨時表,你怎麼能表達all_the_ids_you_processed?我提前對處理後的記錄感到有些不舒服,所以我可以稍後選擇它們,因爲它是侵入性的:需要一個新的「timeStamp」列。另外,時間戳很棘手,因爲時間並不總是單調的:例如它可以倒退(例如,當夏令時間關閉時)。 然後,臨時表是一個非常糟糕的主意嗎? – 2010-01-21 10:53:58

+0

而不是時間戳,使用多值狀態字段。讓未處理的行具有狀態0(說);你做一個更新,將狀態設置爲1(意味着正在處理中),然後執行處理,然後執行另一個更新以將狀態設置爲2(表示進入處理)。 – 2010-01-21 21:29:38

+0

是的,我想這可以解決問題,因爲我描述了它。但我最終決定記住客戶端應用程序中已處理記錄的ID。 – 2010-01-23 22:22:58

相關問題