3

私の理解では、Apache は着信要求ごとに個別の PHP プロセスを作成します。つまり、次のようなコードがある場合:

  1. レコードが存在するかどうかを確認する
  2. レコードが存在しない場合は作成する

では、これは競合状態の影響を受けやすいのではないでしょうか? 2 つのリクエストが同時に受信され、両方が同時に (1) にヒットした場合、両方とも false に戻り、両方とも新しいレコードを挿入しようとします。

もしそうなら、人々はこれにどのように対処しますか?これら 2 つのリクエストの周りに MySQL トランザクションを作成することで問題は解決しますか、それとも完全なテーブル ロックを行う必要がありますか?

4

4 に答える 4

3

私の知る限り、異なる接続間でトランザクションを作成することはできません。たぶん1つの解決策は、チェックしている列を一意に設定することです。このように、に2つの接続が行われ1010存在しない場合。どちらもを作成しようとします10。最初に行の挿入を終了し、すべてが順調です。その場合、列が一意ではないため、1秒遅れて接続が失敗します。スローされた例外をキャッチすると、その後SELECTデータベースからレコードを取得できます。

于 2013-03-08T01:06:49.543 に答える
2

正直なところ、私はこのような状況に遭遇したことはほとんどありません。多くの場合、ビジネス要件を再評価することで軽減できます。2 人の異なるユーザーがまったく同じデータを挿入しようとしていたとしても、アプリケーションではなくユーザーの重複の管理を延期します。

ただし、アプリケーション ロジックに一意の制約を強制する理由がある場合は、INSERT IGNORE... ON DUPLICATE KEY UPDATE...クエリを使用します (もちろん、テーブル内の対応する UNIQUE インデックスを使用します)。

于 2013-03-08T01:33:29.070 に答える
0

Apacheは、「着信要求ごとに個別のPHPプロセスを作成する」ことはありません。プロセスのプール(デフォルト、プリフォークモード)またはスレッドのいずれかを使用します。

おっしゃるように、競合状態はDB「デッドロック」を参照(または原因)することもあります。@データベースのデッドロックとは何ですか?

はい、必要に応じてトランザクションを使用することでこの問題を解決できます。
レコードが存在するかどうかを確認し、トランザクション内でレコードを作成することにより、操作全体がアトミックになります。
したがって、他の要求は重複レコードを作成しようとしません(または、実際のクエリによっては、不整合を作成したり、実際のデッドロックを入力したりしません)。

また、MySQLは(まだ)ネストされたトランザクションをサポートしていないことに注意してください。最初のコミットですべてがコミットされるため、トランザクション内にトランザクションを含めることはできません。

于 2013-03-08T01:30:21.997 に答える
0

2 番目のステップでエラーを処理するだけで十分だと思います。2 つのプロセスがレコードを作成しようとすると、MySQL テーブルを適切に構成している限り、そのうちの 1 つが失敗します。適切なフィールド全体で UNIQUE を使用することは、トリックを実行する 1 つの方法です。

于 2013-03-08T01:28:09.233 に答える