29

ユーザー名がデータベースに存在するかどうかを検索し、そのユーザー名を新しい行としてデータベースに挿入できることを保証するにはどうすればよいSELECTですINSERTか?

あたかも存在しない行をロックしているかのようです。ユーザー名"Foo"で存在しない行をロックしたいので、データベースに存在するかどうかを確認し、存在しない場合は中断することなくデータベースに挿入できます。

私は使用LOCK IN SHARE MODEしてFOR UPDATE存在することを知っていますが、私が知る限り、それはすでに存在する行でのみ機能します。この状況で何をすべきかわかりません。

4

5 に答える 5

31

上記の答えは SELECT ... FOR UPDATE が同時セッション/トランザクションが同じレコードを挿入するのを防ぐという点で真実ですが、それは完全な真実ではありません。私は現在同じ問題に取り組んでおり、次の理由により、その状況では SELECT ... FOR UPDATE はほとんど役に立たないという結論に達しました。

並行トランザクション/セッションは、まったく同じレコード/インデックス値に対して SELECT ... FOR UPDATE を実行することもでき、MySQL はエラーをスローすることなく、すぐに (非ブロッキングで) 喜んでそれを受け入れます。もちろん、他のセッションがそれを行うとすぐに、あなたのセッションもレコードを挿入できなくなります。あなたも他のセッション/トランザクションも、状況に関する情報を取得せず、実際に挿入しようとするまで、レコードを安全に挿入できると考えています。次に挿入しようとすると、状況に応じて、デッドロックまたは重複キー エラーが発生します。

つまり、SELECT ... FOR UPDATE は、他のセッションがそれぞれのレコードを挿入するのを防ぎますが、SELECT ... FOR UPDATE を実行してそれぞれのレコードが見つからない場合でも、実際にはできない可能性があります。そのレコードを挿入します。私見、それは「最初のクエリ、次に挿入」メソッドを役に立たなくします。

この問題の原因は、MySQL が存在しないレコードを実際にロックする方法を提供していないことです。2 つの同時セッション/トランザクションは、存在しないレコードを同時に "FOR UPDATE" でロックできます。これは実際には不可能であり、開発を大幅に困難にします。

これを回避する唯一の方法は、セマフォ テーブルを使用するか、挿入時にテーブル全体をロックすることです。テーブル全体のロックまたはセマフォ テーブルの使用の詳細については、MySQL のドキュメントを参照してください。

ちょうど私の2セント...

于 2015-07-02T12:09:33.773 に答える
27

にインデックスがあるusername場合 (そうである必要があります。そうでない場合は、1 つ追加し、できれば 1 つ追加しますUNIQUE)、 を発行するSELECT * FROM user_table WHERE username = 'foo' FOR UPDATE;と、同時トランザクションがこのユーザーを作成できなくなります (「前の」および「次の」一意でないインデックスの場合に可能な値)。

(条件を満たす)適切なインデックスが見つからない場合WHERE、効率的なレコード ロックは不可能であり、テーブル全体がロックされます*。

このロックは、 を発行したトランザクションが終了するまで保持されSELECT ... FOR UPDATEます。

このトピックに関するいくつかの非常に興味深い情報は、これらのマニュアル ページで見つけることができます。

*実際、レコード ロックは実際にはインデックス レコードのロックであるため、効率的と言えます。適切なインデックスが見つからない場合は、既定のクラスター化インデックスのみを使用でき、完全にロックされます。

于 2013-06-12T15:23:37.140 に答える
10

存在しないレコードのロックは、MySQL では機能しません。それに関するいくつかのバグレポートがあります:

1 つの回避策は、新しいレコードが挿入される前に既存のレコードがロックされるミューテックス テーブルを使用することです。たとえば、sellers と products の 2 つのテーブルがあります。売り手は多くの商品を持っていますが、重複した商品を持ってはなりません。この場合、sellers テーブルをミューテックス テーブルとして使用できます。新しい製品が挿入される前に、販売者の記録にロックが作成されます。この追加のクエリにより、特定の時点で 1 つのスレッドのみがアクションを実行できることが保証されます。重複なし。デッドロックなし。

于 2016-06-12T03:56:05.533 に答える