2017-05-03 94 views
0

我需要運行一個PHP腳本,我要確保沒有在同一時間運行多個腳本。如何使用mysql數據庫管理單線程作業?

我使用MySQL和我雖然對這一解決辦法:

我建立了波紋管數據庫:

 job_id    | task_id | last_updated_time (AUTO UPDATE) 
    "sending_emails"    77238  2107-5-3 12:2:2 

運行我創建隨機任務ID的腳本之前,我運行一個查詢更新task_id。

$task_id = generate_random_task_id(); 
    $query = " 
        UPDATE 
         jobs 
        SET 
         task_id = $task_id 
        WHERE 
         task_id = $task_id 
         OR 
         NOW() - last_updated_time > 30 
        LIMIT 1 
      " 

/* 
    Then I need to check if there was an update, if yes then I will run the script otherwise i will stop since there is already another script running 
*/ 

$query = "SELECT JOB_ID WHERE taks_id = $task_id " 
$result = run($query) 
if(! isset($result[JOB_ID])){ 
    DIE(); 
} 

有兩種腳本可以同時運行嗎?

回答

0

不,他們不能在同一時間運行,here's MySQL的文檔有關UPDATESELECT,這就是它說:

UPDATE ... WHERE ...設置一個獨佔的next鍵鎖定搜索遇到的每個記錄 。但是,只有一個索引記錄鎖定要求 該鎖採用了獨特的索引搜索 唯一行的行語句。

Here's更多關於共享和獨佔鎖:

共享(S)鎖定允許持有鎖讀取 行交易。

獨佔(X)鎖允許持有鎖到 更新或刪除行的事務。

如果事務T1持有行r獨佔鎖(X),從不同的事務T2爲任一類型的於r 的鎖的請求 不能被立即准予。相反,交易T2必須等待 事務T1釋放其對行r鎖。

0

是有每一個機會,你可以再次運行相同的任務。

有兩個明顯的解決方案。

一個是打開一個MySQL連接,然後獲得使用短超時使用GET_LOCK()鎖 - 如果你獲得該鎖,那麼你是好去。您需要在腳本的整個生命週期中維護數據庫連接。

或者,您可以在finish_time上創建一個具有唯一約束的表,使用null結束時間插入記錄以指示開始(如果已經有空結束時間爲空的記錄,將會失敗),然後將finish_time更新爲NOW()完成時。

但是使用數據庫來代表一個正在運行的任務的狀態,只有當任務是lossely再加但高可用集羣內運行是有道理的 - 這意味着該DATABSE也聚集。集羣的性質(NDB,asych,semi-sync,multi-master)對實際中的行爲有很大的影響。

OTOH如果不是這樣的話,那麼用數據庫來表示狀態是解決問題的錯誤方法。

+0

謝謝你的回答,但我不確定爲什麼finish_time可以工作,而我的工作不起作用? –

+0

您能否看看@Darshan Mehta的答案! –

+0

撇開沒有指定間隔的時間在SQL中進行計算的複雜性,只有您能夠*保證執行時間少於30秒才能滿足您的目標。根據數據庫中的併發模型,還會出現競爭條件。此外,在您的示例中,您的任務ID生成中的熵值非常低 - 如果您以高頻率運行此操作,則會在某個時間點發生碰撞。我需要繼續嗎? – symcbean

0

是的,他們可以同時運行。 如果你希望他們在同一時間運行一個SELECT 查詢應改爲:

SELECT JOB_ID WHERE taks_id = $task_id LOCK IN SHARED MODE 

在這種情況下,它使用了一個讀鎖定。

無論您使用NDB還是InnoDB,這都是一樣的。