3

競合状態を防ぐために次のコードを使用しても安全ですか?(keyおよびstatusフィールドと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

行ロックをシミュレートするために、MySqlでGET_LOCKおよび関数を確認できます。RELEASE_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 に答える
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 に答える