🔒
ギャップロックについて簡単に調べた
先日、業務でとあるインシデントが発生したのですが、その原因がギャップロックでした。
個人的にはそのタイミングでギャップロックを初めて知ったので、「ギャップロックとは何か」「どういうときに発生するのか」などについて簡単に調べてみたので、そのことについて個人的メモとしてまとめてみます。
ギャップロックとは
ギャップロックとは、レコードの間に対して発生するロックのことです。
なぜ発生するのか
ファントムリードを防ぐためにロックがかかります。
ファントムリードとは、あるトランザクションでデータを追加or削除した場合に、他のトランザクションで読み込んだ場合に異なるデータを読み込んでしまうことを指します。
どのような場合に発生するのか
実際にどのような現象なのか確認してみましょう。
DBの状態は以下の通りです。
mysql> select * from users;
+----+--------+
| id | name |
+----+--------+
| 10 | Taro |
| 20 | Jiro |
| 30 | Saburo |
| 40 | Shiro |
| 50 | Goro |
+----+--------+
5 rows in set (0.01 sec)
トランザクション1(T1)
範囲指定してselect ~ for updateを実行してみます。
select * from users where id >= 15 and id <= 25 for update;
問題なく実行できます。
トランザクション2(T2)
T1で指定した範囲にレコードをインサートしようとしてみます。
insert users (id, name) values (23, 'hanako');
ここで待ちが発生します。これはT1で指定した15~25の間にギャップロックが発生しているからです。
select ~ for updateじゃなかったらどうなる?
先ほどはselect ~ for updateで指定しましたが、selectの場合はどうなるのでしょうか?
トランザクション1(T1)
以下のクエリを実行します。
select * from users where id >= 15 and id <= 25;
もちろん実行できます。
トランザクション2(T2)
次に以下のクエリを実行します。
insert users (id, name) values (23, 'hanako');
今度は実行できました。
とうやらギャップロックはselect ~ for updateでレコードを取得した場合に発生するみたいですね。
まとめ
以上が簡単なギャップロックの説明になります。
インデックスを張っているorいない、プライマリーキーorセカンダリーキーなども挙動に影響するっぽいのですが、今回は調べる余裕がなかったので、またの機会に調査してみようと思います。
Discussion