2009-10-16 67 views
2

我有一個數據庫表,我需要拉一行,測試用戶輸入的匹配,然後更新行來標識匹配的用戶。如果出現競爭狀況,我需要確保第一位用戶的更新不會被其他用戶覆蓋。PHP,mysqli和表鎖?

要做到這一點,我打算:
1.逐行讀取
2.鎖定表再次
3.閱讀行,並比較原始行
4.如果相匹配的行更新,否則什麼也不做(另一個用戶已經更新了該行)

根據我在Google上找到的信息,我預計鎖表語句會阻塞,直到獲得鎖。我在PHP中設置了一個小測試腳本,它會停頓10秒,以便我有時間手動創建競爭條件。

// attempt to increment the victor number 
$aData["round_id"] = $DATABASE["round_id"]; 

// routine to execute a SELECT on database (ommited for brevity) 
$aRound = $oRound->getInfo($aData); 

echo "Initial Round Data:"; 
print_r($aRound); 

echo "Locking..."; 
echo $oRound->lock(); 

echo "Stalling to allow for conflict..."; 
sleep(10); 
echo "Awake..."; 

$aLockedRound = $oRound->getInfo($aData); 
if($aRound["victor_nation"] == $aLockedRound["victor_nation"]){ 
    $aData["victor_nation"] = $aRound["victor_nation"] + 1; 
    $oRound->update($aData); 
    echo "Incremented Victor Nation"; 
} 

在鎖定常規定義爲

function lock(){ 
     global $oDatabase; 
     $iReturn = 0; 

     // lock the table 
     $iReturn = $oDatabase->m_oConnection->query("LOCK TABLES round WRITE");  
     return $iReturn; 
    } 

以上,$oDatabase->m_oConnection的是,我用它來在數據庫上執行準備語句的mysqli的連接。

當我運行我的測試腳本時,我啓動第一個用戶並等待「停頓以允許衝突...」,然後啓動第二個腳本。關於第二個腳本,我希望它阻止在「鎖定...」,但是,第二個腳本也繼續「停頓以允許衝突......」。由於LOCK陳述似乎沒有被阻塞,也沒有返回獲取鎖的任何指示器(返回值被回顯並且空白),所以我不清楚我是否實際上獲取了鎖。即使我是,我不知道如何繼續。

任何指針?

+0

Innodb或MyIsam表? – 2009-10-16 20:15:19

+0

該表是MyIsam – 2009-10-20 00:42:57

回答

3

故障排除:您可以通過嘗試使用未鎖定的另一個表來測試表鎖成功。如果您獲得了鎖定,則嘗試寫入未包含在鎖定語句中的表格應該會生成錯誤。

您可能需要考慮替代解決方案。作爲where子句的一部分,不要鎖定,而是執行包含已更改元素的更新。如果您讀取數據後發生更改,則更新將「失敗」並返回零行修改。這消除了桌面鎖,以及隨之而來的所有可怕的恐怖,包括死鎖。 Innodb或MyIsam表嗎?

+0

謝謝查爾斯!完全避免使用where claus工作得很好。 – 2009-10-20 00:45:06