上記の答えは、SELECT ... FOR UPDATEは同時セッション/トランザクションが同じレコードを挿入することを防止しますが、完全な真実ではありません。私は現在同じ問題を抱えていますが、SELECT ... FOR UPDATEがそのような状況ではほとんど役に立たないという結論に達しました。
同時トランザクション/セッションでもSELECT ... FOR UPDATEと同じレコード/インデックス値を使用すると、MySQLは即座に即座に(非ブロッキングで)エラーをスローすることなく受け入れます。もちろん、他のセッションがそれをしたらすぐに、あなたのセッションもレコードを挿入することはできません。あなたや他のセッション/トランザクションは状況に関する情報を得ておらず、実際にそうしようとするまでレコードを安全に挿入できると思います。状況に応じて、挿入しようとすると、デッドロックまたは重複キーエラーが発生します。
つまり、SELECT ... FOR UPDATEは、SELECT ... FOR UPDATEを実行してもそれぞれのレコードが他のセッションに挿入されるのを防ぎますが、それぞれのレコードが見つからない場合は、実際にそのレコードを挿入することはできません。 IMHOは、「最初のクエリを挿入して」メソッドを役に立たなくします。
この問題の原因は、MySQLには、には実際にはのレコードをロックする方法がありません。 2つの同時セッション/トランザクションでは、存在しないレコード "FOR UPDATE"を同時にロックすることができます。これは実際には不可能であり、開発を大幅に困難にします。
これを回避する唯一の方法は、セマフォー・テーブルを使用するか、挿入するときにテーブル全体をロックすることです。テーブル全体のロックやセマフォーテーブルの使用に関する詳細は、MySQLのマニュアルを参照してください。
ちょうど私の2セント...
インデックスを持たないものに対して新しい行を追加するとどうなりますか?それはインデックスなしでテーブル全体をロックしますか? – xLite
はい、私はそれに言及するのを忘れました。レコード・ロックに適切な索引が見つからない場合は、表全体が読み取り専用になります。 – RandomSeed
'username'カラムに' UNIQUE'インデックスがなく、 'user_id'カラムに' PRIMARY'がある場合はどうなりますか? 'FOR UPDATE'で検索すると、ユーザー名 'foo'がロックされていることが確認できますか?私が完全に気付いていないかもしれない落とし穴がありますか?例えば。 'user_id'と' username'の両方が同時にインデックスを持っているなら( 'PRIMARY'と' UNIQUE')、ロックが不可能でエラーや何かが出るでしょうか?私はこれについてまだかなり謝っています。それはややばかな質問です。返信いただきありがとうございます! – xLite