行レベル ロック内では、InnoDB
は
ネクスト キー ロック
と呼ばれるアルゴリズムを利用します。InnoDB
は、それがテーブルのインデックスを検索やスキャンする時に、遭遇したインデックス
レコード上で共有、または専用ロックを設定する、という方法で行レベル
ロックを実行します。従って、行レベル
ロックは実際はインデックス レコード
ロックであるという事になります。
InnoDB
がインデックス
レコード上で設定するロックは、そのインデックス
レコードの前の 「ギャップ」
にも影響を与えます。もしユーザがインデックス内のレコード
R
上に共有または専用ロックを持っていたら、別のユーザはインデックスの順番で
R
の直前に新しいインデックス
レコードを挿入する事はできません。このようなギャップのロックは、一般的に
「ファントムの問題」
と呼ばれる物を防ぐ為に行われます。後で選択した行内のいくつかのカラムを更新するつもりで、100よりも大きい値の識別子を持つ
child
テーブルから全ての子供を読み、ロックしたいと仮定します:
SELECT * FROM child WHERE id > 100 FOR UPDATE;
id
カラム上にインデックスがあると仮定してください。クエリは、id
が100以上の最初のレコードから、そのインデックスをスキャンします。もしインデックス
レコード上に設定されたロックがギャップに挿入された物をロックしなければ、その一方で新しい行がテーブルに挿入されるでしょう。
もし同じトランザクション内で同じ
SELECT
を実行すると、クエリから返された結果セット内に新しい行を見つける事ができます。これは、トランザクションの分離原理に反しています:トランザクションは、読み取ったデータをトランザクションの最中に変更させない為に起動する必要があります。行セットをデータ項目であるとみなすと、新しい
「ファントム」
の子供はこの分離原理に違反します。
When InnoDB
がインデックスをスキャンする時、インデックス内の最後のレコードの後のギャップをロックする事もできます。それは前出の例の中で起きています:InnoDB
によって設定されるロックは、id
が100以上になるテーブルへの挿入を防ぎます。
アプリケーション内に一意性チェックを実装する為にネクスト キー ロックを利用する事ができます:共有モードでデータを読み取り、挿入しようとする行に重複が見られなければ、行を確実に挿入できます。また、読み取り中は対象となる行の後続の行にネクスト キー ロックが設定されて、第三者による重複行の挿入を防ぎます。このように、ネクスト キー ロックによって、テーブル内に存在しない物を 「ロック」 する事ができます。