2012-06-22 51 views
3

使用下面的代碼來防止競爭條件安全嗎? (keystatus領域和mysql_affected_rows用於實現鎖定)使用mysql_affected_row來防止競爭條件

$mres = mysql_query("SELECT `values`, `key`, `status` 
        FROM `test` 
        WHERE `id` = 1"); 
$row = mysql_fetch_array($mres); 
if($row['status'] != UPDATING) { 
    $mres = mysql_query("UPDATE `test` SET 
          `status` = UPDATING, 
          `key` = `key` + 1 
         WHERE `id` = 1 AND `key` = ".$row['key']); 
    if($mres && mysql_affected_rows()) { 
     //update here safely and then... 
     mysql_query("UPDATE `test` SET 
         `status` = NOT_UPDATING, 
         `key` = `key` + 1 
        WHERE `id` = 1"); 
    } 
} 

我的測試表明,無論它是不是安全的,或者我應該尋找在我的代碼精心隱藏的錯誤。 表是MyISAM

+0

這似乎是正確的,唯一的錯誤可能是如果'id'不是表中的PRIMARY/UNIQUE鍵。另外,您需要在所有情況下都將'UPDATING'作爲字符串。 – hjpotter92

回答

0

在檢索值之前,應先「獲取鎖定」。否則,他們可能會在你鎖定之前改變。

$mres = mysql_query("UPDATE `test` SET 
          `status` = 'UPDATING' 
         WHERE `id` = 1 AND `status` = 'NOT_UPDATING'"); 
if ($mres && mysql_affected_rows()) { 
    // got the lock 
    // now select and update 
} 
  • id最好是一個獨特的領域在數據庫或事情可能表現得非常怪異
  • 我看不出一個理由來增加關鍵
  • 通知我引用字符串'UPDATING''NOT_UPDATING'在SQL
  • 在你的代碼中,你應該也檢查了$row['status']在比較php常量之前是否有一個有意義的值(假如它是false/null?)UPDATING
  • 希望你瞭解足夠的PHP知道PHP字符串應該被引用。
+0

也許UPDATING和NOT_UPDATING是常量? –

+0

雅我在辯論這個......我真的懷疑它。該代碼聞起來有人不幸地從學習php/mysql的十億蹩腳的php/mysql博客教程中弄髒了互聯網。 – goat

+0

是的,但我仍然喜歡這個問題。然而,這是否是防止競爭狀態的好方法?爲什麼不使用'GET_LOCK()'? –

0

您可以在MySql中檢查GET_LOCKRELEASE_LOCK函數以模擬行鎖。

http://dev.mysql.com/doc/refman/5.1/en/miscellaneous-functions.html#function_get-lock

通過這種方法,你就不需要更新的行。如果出現問題,也可以使用mysql_affected_rows()您可以使用始終鎖定的行來完成(例如,如果腳本在釋放行之前通過將行狀態更新爲NOT_UPDATING而崩潰)。連接終止時,自動釋放鎖GET_LOCK