最終更新日: 2026-08-25
TOP(About this memo)) > 一覧(RDB) > ロック・排他制御(MySQL)
MySQLの特徴として、ギャップロック、ネクストキーロックがある。
レコードロック: インデックスレコードのロック。
ギャップロック: インデックスレコード間にあるギャップのロック、または先頭のインデックスレコードの前や末尾のインデックスレコードのあとにあるギャップのロック。
ネクストキーロック: インデックスレコードに対するレコードロックと、そのインデックスレコードの前にあるギャップに対するギャップロックとを組み合わせたもの。
(参考) InnoDB のロック方法
select * from performance_schema.data_locks;
LOCK_MODE:
IX インテンション排他ロック、IS インテンション共有ロック
ISやIXに対しては競合しないが、SやXには競合する。select * from performance_schema.data_locks で見ると2つのロックが確認できる。テーブルにXがかけられている場合は、IXもISもできない。S 共有ロックX 排他ロックREC_NOT_GAP
NOT GAPと書いてあるのはギャップロックではないことを明示している)。例えば、排他レコードロックされている場合は「X, REC_NOT_GAP」という形で表示される。GAP
LOCK_DATA: LOCK_TYPE='RECORD' の場合はロックされたレコードの主キー値、それ以外の場合はNULL。
ロックしているトランザクションを特定してkillする:
SELECT trx_rows_locked FROM information_schema.INNODB_TRX; -- スレッドIDなどがわかる
show processlist;
KILL 19784;
インデックスやユニーク制約がついていないカラムに対してWHEREで条件指定して占有ロックをかけると、テーブルロックになってしまう。
複数条件の場合は、1つでもインデックスやユニーク制約がついている条件が入っていれば、対象の行のみの行ロックになる(?)。
(参考) MySQLのロックについて
(参考) MySQLロック関連メモ
SQLが空振りした際に取得される(?)。例えば BETWEEN 3 AND 6 で取得した際、テーブルに3, 5, 8しかない場合は6が空振りしているので、8までギャップロックが取られる。これはファントムリードを回避するためとされている。
(IME) 「仮に他の処理で8が挿入されても、次に BETWEEN 3 AND 6 を行ったときには関係ないのでは」と最初は疑問に思ったが、MySQLはインデックスを使ってロックをかけているため、このような挙動になるらしい(?)。
無効化したい場合は、トランザクション分離レベルをREAD COMMITTEDに変更する。
ギャップロックの目的は、REPEATABLE READでファントムリードを回避するため。ISO SQLの仕様では、REPEATABLE READにおいてファントムリードは許容されるが、InnoDBでは発生しないようになっている。これは、ギャップロックによって走査した範囲への挿入をロックすることで実現している。