InnoDB は、行レベルのロックでネクストキーロックと呼ばれるアルゴリズムを使用します。 InnoDB が行レベルロックを行うのは、テーブルのインデックスを検索またはスキャンする際に、検出したインデックスレコードに共有ロックまたは排他ロックを設定するためです。このため、行レベルロックは正確にはインデックスレコードロックと呼ばれます。
InnoDB
がインデックスレコードに設定するロックは、そのインデックスレコードの前の
'ギャップ'
にも影響します。あるユーザがインデックスのレコード
R
に共有ロックまたは排他ロックを設定すると、他のユーザはインデックス順で
R
の直前に新しいインデックスレコードを挿入できなくなります。
このようなギャップのロックには、いわゆるファントムの問題を回避する目的があります。たとえば、テーブル
CHILD
から 100 より大きい
ID
を持つすべてのレコードを読み取ってロックし、選択したレコードに対してフィールドを更新するとします。
SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;
テーブル CHILD
のカラム
ID
にインデックスがあるとします。クエリでは、ID
が 100
より大きい最初のレコードから順にそのインデックスがスキャンされます。
ここで、インデックスレコードに設定されたロックがギャップで行われる挿入をロックアウトしないと、テーブルに新しいレコードが挿入される可能性があります。その場合に、トランザクションで次のステートメントをもう一度実行してみます。
SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;
すると、クエリから返される結果セットに新しいレコードが含まれることになります。 これは、トランザクションの分離の原則に反します。 つまり、トランザクションの実行中は、読み取ったデータが変化しないことが必要です。一組のレコードを 1 つのデータ項目と見なすと、新たな 'ファントムの' レコードによって、この分離の原則が破られることになります。
InnoDB
では、インデックスをスキャンする際に、インデックス内の最後のレコードの後のギャップもロックできます。前の例と同様に、InnoDB
が設定したロックによって、テーブル内の
ID
が 100
より大きい箇所への挿入が防止されます。
ネクストキーロックを使用して、アプリケーションに一意性のチェックを実装できます。共有モードでデータを読み取り、挿入しようとするレコードに重複が見られなければ、レコードを確実に挿入できます。また、読み取り中は対象となるレコードの後続のレコードにネクストキーロックが設定されて、第三者による重複レコードの挿入を防ぎます。このように、ネクストキーロックによって、テーブル内に存在しないものを 'ロック' することができます。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.