1

InnoDB ストレージ エンジンを使用する Web アプリケーションでは、次のシナリオでデータベース ロックを適切に利用できませんでした。

3 つのテーブルがあり、それらを と とaa呼びarますai

aa基本レコード、たとえば記事を保持します。arは、各aaレコードに関連する情報と、 と の関係aaを保持しarます1:m

のレコードは、 からのレコードが最初に読み込まarれたときに保存されます。問題は、2 つの要求が (ほぼ) 同じ時刻に開始されて (関連するレコードが に保存されていない) レコードを読み取ると、レコードが重複することです。aaaaarar

状況を理解するのに役立つ疑似コードを次に示します。

  • aa要求されたレコードを読み取ります。

  • arテーブルをスキャンして、指定されたaaレコードに既に何かが格納されているかどうかを調べます。(そうではないと仮定します。)

  • 特定のレコードaiを何に保存するかを調べるには、相談してください。(やや無関係に思えますが、ロックにも関与する必要があることがわかりました...間違っている可能性があります。)araaai

  • 数行挿入してar

これが私が達成したいことです:

  • aa要求されたレコードを読み取ります。

TRANSACTIONS LOCKarを使用するかどうかに関係なく、読み取りを試行する後続のリクエストは、この時点でar1 つが終了するまで待機します。

  • arテーブルをスキャンして、指定されたaaレコードに既に何かが格納されているかどうかを調べます。(そうではないと仮定します。)問題は、2 つの同時要求の場合、指定されたレコードにレコードが存在しないことを検出し、両方とも同じ行を 2 回挿入することです。araaそれ以外の場合、このシーケンスは中断され、INSERT は発生しません。

  • 特定のレコードaiを何に保存するかを調べるには、相談してください。(やや無関係に思えますが、ロックにも関与する必要があることがわかりました...間違っている可能性があります。)araaai

  • 数行挿入してar

ロックオンを解除するar

単純に思えますが、重複を回避できませんでした。Bash シェル (wget を使用) で単純なコマンドからの同時要求をテストしています。

私は、 http: //dev.mysql.com/doc/refman/5.5/en/innodb-lock-modes.htmlhttp://dev.mysql. com/doc/refman/5.5/en/innodb-locking-reads.htmlロックを利用するいくつかの方法を試しましたが、まだ運がありません。

テーブル全体をarロックしたい (INSERT が複数のリクエストから発生するのを防ぎたいため) このテーブルとのやり取りをさらに試行して、最初のロックが解除されるまで待機させます。しかし、ドキュメントには「テーブル全体」がロックされているという言及が 1 つだけありますが (最初のリンク先ページのインテンション ロックのセクション)、それについては詳しく説明されていないか、それを達成する方法を理解できませんでした。

誰かが正しい方向を指すことができますか?

4

1 に答える 1