0

データベースと1つのテーブル(innoDB):テーブルがあります。

このテーブルの行は、m1とm2です。

1ページに2つの送信ボタンがあります。

送信1はこれを行います:

Database::q('UPDATE table SET m1 = ?s, m2 = ?i WHERE id = ?i', $n, 0, $ID);

送信2はこれを行います:

Database::q('UPDATE table SET m2 = ?s WHERE id = ?i', $n2, $ID);

問題:ユーザーが両方のフォームを同時に送信した場合。送信1で100000($ n)、送信2で50($ n2)としましょう。更新後の結果は、m1で99 950、m2で100000になります。

どうすればこれを防ぐことができますか?トランザクションを使用してみましたが、それでも正しく機能しません。

この構文は正しいですか?実行、クエリ、実行のいずれかをいつ使用するかわかりません。

try {
   Database::beginTransaction();
   Database::q('..');
   Database::commit();
} catch (Exception $e) {
   Database::rollBack();
   echo 'ERROR!';
}

これは私が使用しているデータベースクラスです:http: //pastebin.com/PfsiYysX

4

2 に答える 2

0

ユーザーが両方のフォームを同時に送信した場合

1つのファイルまたは2つの別々のphpファイルに対して2つのhttpリクエストがあることを意味します-実際には問題ではありません。いずれにせよ、この問題を回避する方法はありません(トランザクションもありません)。

トランザクションは、次々に実行する必要のある一連のクエリを保護するために使用されます。それらは、実行前にSQLエンジンに認識されている必要があります。2つのリクエストで、異なる単一ステートメントクエリを送信する場合、それは不可能です。

解決策は、javascriptを介してボタン2を非アクティブ化することです。1つ1が押され、その逆も同様です。ただし、これは、jsが有効になっている正常に動作するクライアント(セキュリティ対策なし!)にのみ有効です。

于 2013-01-14T14:29:42.517 に答える
0

マーティンが示唆しているように、一部のJavaScriptは、両方のボタンを誤って押すのを防ぎます。ただし、すべての場合に機能するわけではなく、両方の形式の意図的な送信に対する保護を提供するものではありません。ただし、実際の効果的な制御を操作に適用するポイントにほとんどのユーザーが到達するのを防ぎます。

より安全な解決策は、使い捨てのCSRFトークン(両方の形式で同じトークンのコピー)を組み込むことです-最初のリクエストでトークンをチェックして期限切れにします。これに伴う問題は、ユーザーがセッションを分割した場合(新しいウィンドウを開く場合)に障害があるとユーザーが認識する可能性があることです。これを軽減する方法はいくつかありますが、アプリケーションの実装方法の具体的な詳細によって異なります。

より良い解決策は、データが初期状態にあるときに両方の更新を許可し、その後の更新を許可しない有限状態マシンとしてモデル化することです。私は例を提供したと思いますが、あなたが提供したデータからはそれは不可能です。したがって、代わりにこれを考慮してください。ユーザーが買い物かごをいっぱいにして、チェックアウトに行きます。この時点で、彼らには2つの選択肢があります-バスケットを購入するか廃棄するかです。彼らが「購入する」をクリックした場合は、ステータスを「購入」に設定し、バスケットのステータスは「チェックアウト時」になります。これが成功した場合は、購入処理に進みます。彼らが「破棄」をクリックした場合、バスケットのステータスを「破棄」に変更します。ステータスは「チェックアウト時」です。成功した場合は、クリーンアップを続行します。いずれかの操作が成功しない場合は、次に、エラーを報告します。各操作は自動コミットする必要があることに注意してください-これはロックを使用しません。

于 2013-01-14T14:42:02.120 に答える