名前列に一意の制約があると仮定すると、それぞれinsert
がロックを取得します。2回目に同時に挿入しようとするスレッドは、1回目insert
が成功または失敗するまで待機します(txコミットまたはロールバック)。
最初のトランザクションが成功すると、2番目のトランザクションは一意キー違反で失敗します。そして、あなたはそれがすでに存在していることを知っています。
トランザクションごとに1つの挿入がある場合は、「OK」です。トランザクションごとに複数の挿入がある場合、デッドロックが発生する可能性があります。
各スレッドは文字列名を渡します。その名前がテーブルに存在する場合、データベースは行のIDを返す必要があります。名前がまだ存在しない場合は、名前を挿入してIDを返す必要があります。
全体として、アルゴは次のようになります。
1 read row with name
2.1 if found, return row id
2.2 if not found, attempt to insert
2.2.1 if insert succeeds, return new row id
2.2.2 if insert fails with unique constraint violation
2.2.2.1 read row with name
2.2.2.2 read should succeed this time, so return row id
一意のインデックスで高い競合が発生する可能性があるinsert
ため、しばらくの間ブロックされる可能性があります。その場合、トランザクションはタイムアウトになる可能性があります。ストレステストを行い、負荷で正しく機能するまで構成を調整します。
また、一意の制約違反の例外またはその他の例外が発生するかどうかを確認する必要があります。
また、これはトランザクションごとに1つの挿入がある場合にのみ機能します。そうでない場合、デッドロックが発生する可能性があります。
また、手順1の行を「」で読み取ってみることができますselect * for update
。この場合、同時挿入がコミットまたは成功するまで待機します。これにより、インデックスの競合によるステップ2.2.2でのエラーの量をわずかに減らすことができます。