web-dev-qa-db-ja.com

MySQLでテーブルをロックせずに同時実行を管理する方法は?

私たちのphpアプリには、受付で受け取った注文を記録するテーブルがあります。最大7つのエージェント/アクティブアカウントを持つことができるので、毎回テーブルをロックする必要なしに、どのようにして注文テーブルの同時実行性を管理することができますか。

問題は次のとおりです。

  1. メインテーブルに行を挿入する前に、顧客に対して実行する一連のチェックアップが存在する必要があります。これにより、複数の選択、次に挿入が課されます。

  2. オーダーは、エージェントによって1つずつではなく、バッチによってロードされます。データベースへのアクセスが禁止されているため、テーブルをロックすると、注文の登録をやり直すように要求されます。

MySQLの書き込み管理について心配する必要がありますか、それとも実際にロックシステムに進む必要がありますか?

2
Mikahel

並行性と分離は、ここで扱う2つのトピックです。複数のユーザーが同時にシステムを使用する機能と、各ユーザーの作業が他のユーザーの影響を受けないようにする機能です。 RDBMSは、分離レベルとロックを通じてこれを処理します。それはそれらが機能するように設計されている方法です。それは彼らがすることです。アプリケーションアーキテクトとしての私たちの仕事は、要件を満たす設定を選択し、競合が発生する可能性のある時間枠を最小限に抑えるような方法でシステムを構築することです。

このシステムでは、Orderテーブルと他のテーブルの行間の一貫性が必要です。これにはロックが必要です。これがまさにロックの目的です。それらを怖がらないでください。彼らはあなたの友達であり、あなたのデータを保護します。参照テーブルでは、読み取りのみで書き込みではなく共有ロック、できれば行ロックを確実に取得する必要があります。このようにして、複数の並行アクティビティが参照データを共有できます。

注文を書き込むと、排他ロックが作成されます。うまくいけば、新しい行だけで、多分テーブルの上に。したがって、挿入後できるだけ早くトランザクションをコミットすることにより、そのロックを迅速に解放することが重要です。

望まないのは、エージェントが入力している間、これらのロックが保持されることです。これは、コンピュータ用語では永遠です。必ず、入力時に入力を検証しますが、単一のステートメントとしてのみ検証し、データ入力セッション全体にわたるトランザクションでは決して検証しません。次に、最後に、注文が保存されたら、トランザクションを開始し、参照データを再度読み取り、注文を挿入してコミットします。ミリ秒で完了する必要があるすべてのプラットフォーム。他のオペレーターはそれが起こっていることにさえ気付かないでしょう。エラーまたは競合がある場合、エージェントはすぐにフィードバックを受け取り、修正して再送信できます。

代替案はありますが、お勧めしませんが、参考のためにここにリストしてください。非同期のメッセージ処理設計でシステムを構築できます。エージェントがデータを保存すると、データ値ごとに1つの列を持つ単一のステージングテーブルに書き込まれます。検証なし、正規化なし。 1つの挿入とデータの永続化。 7つのオペレーターを使用すると、DBで一度に2つの操作が行われる可能性もほとんどありません。 2番目のプロセスは、このテーブルをポーリングして、一度に1行を読み取ります。正規化されたスキーマを検証して書き込みます。結果-成功または失敗-が記録されます。次に、ステージングテーブルの次の行が処理されます。これにより、大幅に複雑な設計を犠牲にしてすべての挿入が完全にシリアル化され、エージェントへの即時フィードバックがなくなり、エラーを修正するための追加のビジネスプロセスとプログラミングの必要性が保証されます。また、これはデータベースに接続している他のプログラムからのアクティビティを保護しません。結局、何かがそれらの命令を読んでいる必要があります。言ったように、お勧めしません。

同時にデータを入力する7つのエージェントは、それほど多くありません。あなたwillこれを処理するシステムを構築できると私は約束します。

4
Michael Green

そのためには楽観的ロックが必要です。

テーブルの順序でitemid + createdat + useridのような一意の制約を作成します。これにより、重複した注文が発生しないことが保証されます。同時に、悲観的なロックを回避します。更新には、行バージョン(Martin Fowlerオフラインロック)などが必要になります。

1
andres