使用mysql_affected_rows来防止竞争条件

时间:2012-06-22 20:05:47

标签: mysql myisam

使用以下代码来防止竞争条件是否安全? (keystatus字段和mysql_affected_rows用于实现锁定)

$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

2 个答案:

答案 0 :(得分: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最好是数据库中的唯一字段,否则事情可能会非常奇怪
  • 我看不出增加密钥的理由
  • 请注意我在sql
  • 中引用了字符串'UPDATING''NOT_UPDATING' 在您的代码中
  • ,在与php常量$row['status']
  • 进行比较之前,您还应该检查UPDATING是否有一个有意义的值(如果它是假/ null?)
  • 希望你能够理解足够的php知道php字符串应该被引用。

答案 1 :(得分: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的锁定在连接终止时自动释放。