2010-03-20 29 views
-2

當有多個PHP腳本並行運行時,每個腳本都對同一個表中的同一條記錄重複進行UPDATE查詢,是否有可能在每個查詢更新表之前存在「滯後時間」?MySql查詢滯後時間/死鎖?

我基本上有5-6個並行運行的PHP腳本實例,它們是通過cron啓動的。每個腳本獲取items表中的所有記錄,然後遍歷它們並處理它們。

但是,爲了避免多次處理同一個項目,我將最後處理的項目的ID存儲在一個單獨的表格中。所以這是我的代碼是如何工作的:

function getCurrentItem() 
{ 
    $sql = "SELECT currentItemId from settings"; 
    $result = $this->db->query($sql); 
    return $result->get('currentItemId'); 
} 

function setCurrentItem($id) 
{ 
    $sql = "UPDATE settings SET currentItemId='$id'"; 
    $this->db->query($sql); 
} 

$currentItem = $this->getCurrentItem(); 

$sql = "SELECT * FROM items WHERE status='pending' AND id > $currentItem'"; 
$result = $this->db->query($sql); 
$items = $result->getAll(); 

foreach ($items as $i) 
{ 
    //Check if $i has been processed by a different instance of the script, and if so, 
    //leave it untouched. 
    if ($this->getCurrentItem() > $i->id) 
    continue; 

    $this->setCurrentItem($i->id); 
    // Process the item here 
} 

但是,儘管所有的預防措施,大部分項目正在處理不止一次。這使我認爲PHP腳本運行的更新查詢與數據庫實際更新記錄之間存在一定的延遲時間。

這是真的嗎?如果是這樣,我應該使用什麼其他機制來確保PHP腳本始終只獲取最新的currentItemId,即使有多個腳本並行運行也是如此。將使用文本文件,而不是數據庫幫助?

回答

1

如果這是平行運行,那麼避免競爭條件的措施很少。

script1: 

getCurrentItem() yields Id 1234 
...context switch to script2, before script 1 gets to run its update statement. 

script2: 
getCurrentItem() yields Id 1234 

並且兩個腳本進程ID 1234

你最好要更新,檢查全有或全無的操作,你不需要設置表項的狀態,但你做這樣的事情(僞代碼):

SELECT * FROM items WHERE status='pending' AND id > $currentItem 

foreach($items as $i) { 
rows = update items set status='processing' where id = $i->id and status='pending'; 
    if(rows == 0) //someone beat us to it and is already processing the item 
    continue; 
    process item.. 
update items set status='done' where id = $i->id; 
} 
+0

在你的代碼中,$ rows是從哪裏設置的?它旁邊是更新查詢。你可以做些什麼? – 2010-03-20 02:29:05

+0

那麼,我不太瞭解PHP。這個想法是,發佈UPDATE將返回no。受影響的行。如果它是0,則意味着'where status ='pending''不匹配,導致其他人同時改變狀態。 – nos 2010-03-20 02:31:57

+0

除了檢查從查詢中受到影響的行以外,還有其他更傻的解決方案嗎?像使用文本文件..? – 2010-03-20 02:47:11

1

你需要的是對任何線程能夠:

  • 找到一個懸而未決的項目
  • 記錄,在這一項目目前正在處理(在settings表)

,它需要做的這些都一氣呵成,沒有任何其他線程的干擾,通過中途。

我建議把整個SQL放在一個存儲過程;這將能夠將整個事件作爲單個事務來運行,這使得它可以避免競爭線程。