データベーステーブルの行への同時アクセスの防止
-
28-10-2019 - |
質問
サポートチームの2人の管理者が、dbテーブルの行に対して同じ機密操作を実行しようとしている場合があります(たとえば、行の値を変更します)。それを防ぐ必要があります。 (テーブルは「myisam」であるため、行のロックはできません)
私はいくつかの解決策を考えました:
フォームに古い値を設定し、送信時に現在の値と比較する ジェネラコディセタグプレ
そして更新する前に: ジェネラコディセタグプレ
ただし、次の状況が発生する可能性があります。
-
ユーザーは金額を9 $から10 $に変更する必要があります
-
admin1は自分のお金を10ドルに変更します
-
ユーザーは1ドルを賢く使うので、現在のお金は再び9ドルになります!
-
admin2は警告なしに自分のお金を10ドルに変更します。
行にタイムスタンプ(updated_at列)設定を作成する
そしてソリューション1と同じことをします。これには、単純なデータ比較以上のものを言っているという利点があります。フォームをいじっている間にデータが変更されたかどうかは確かに言えます。欠点-ソリューション1と組み合わせない限り、どの列が正確に変更されたかを追跡することはできません。 ジェネラコディセタグプレ
そして更新中: ジェネラコディセタグプレ
オブジェクト/アクション固有の名前で長さ0の一時ファイルを作成する
更新中に作成/ロックし、確認する 更新前の存在/日付スタンプ。
更新前: ジェネラコディセタグプレ
今のところ、ファイルの作成が私の好ましいアプローチです。理由は次のとおりです。
-
データベースにアクセスするよりもローカルファイルを作成する方が速いと思います。
-
テーブルにもう1つの列(タイムスタンプ)を追加する必要はありません
-
ファイル名を簡単に変更して、特定の列の変更を確認できます。つまり、mysqlupdateが完了したときにファイル「money_user {$ userid} _modified」を作成できます。
それは正しいですか、それとも私が誤解していることがありますか?
-
解決
UPDATE
操作のWHERE
句で古い値を指定してから、影響を受ける行数を確認できます。
与えられた ジェネラコディセタグプレ
スレッド1が実行されます ジェネラコディセタグプレ
スレッド2が実行されます ジェネラコディセタグプレ
それ以外は、無駄な時間を減らすために、最初に個々の管理者にタスクを割り当てることで、少し早く除外を実装したいと思います。
他のヒント
あなたの場合、ロックが最善のアプローチだと思います。MySQLロックを使用できます: GET_LOCK、RELEASE_LOCK、IS_FREE_LOCK。私の意見では、トランザクションは、フェッチされたデータに対して別のプロセスがタスクを実行している間、行が変更されないことを保証するものではありません。
ただし、特定のケースは、従来の意味でのロックとは関係ありません。私見ですが、管理者が同じ残高変更をダビングしないように、対応する資格情報と説明を使用してトランザクションをログに記録する必要があります。ロックは、行の同時変更から保護できますが、吹き替えの場合の意図的な変更からは保護できません。
データベースの行レベルのロックは、最初の方法で述べた状況を満たしていないと思います。しかし、ファイルの作成がデータベースシステムにアクセスするよりも速いとは思いません。ファイルの作成は、データベースでのCRUDよりも明らかに重いです。
したがって、ロギングテーブルを使用した同様のアプローチを提案します。
- すべてのテーブルには独自の主キー(
pid
など)があります - 誰かが行をいじろうとしたときに、テーブル名とpidをタイムスタンプ付きのログテーブルに記録します。
- クエリを実行する前にログテーブルを確認してください。
InnoDBとトランザクションを見てください。それらは敏感な変化(すなわちバランス)により適しています。
データベースは一元化されたソリューションであるため、一般的に優れています。トラフィックまたは一般的な作業負荷のためにスケーリングする必要がある場合、それらのファイルを同期するのは簡単ではありません。スケーリングの必要性がなく、I / Oレートが良好でない限り、問題ありません。
2つの可能な解決策について言及させてください。これも上記で言及した可能性があります。
管理者アカウントのIDとタイムスタンプを組み合わせた「assigned_id」を追加して、他の誰かが編集している場合にアプリケーションに警告を表示することができます。
別の可能な解決策は、フォームへの入力中に変更が加えられたかどうかを確認することです。ここでは、last_editedタイムスタンプを利用できます。