3

使用以下代码来防止竞争条件是否安全?(keystatusfields 和 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

4

2 回答 2

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 字符串。
于 2012-06-22T20:35:14.710 回答
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当连接终止时,授予的锁会自动释放。

于 2012-06-22T21:13:26.987 回答