[MariaDB]排他ロック・共有ロック
公開日:2026-01-06
更新日:2026-01-06
更新日:2026-01-06
1. 概要
排他ロック・共有ロックについてです。
ロックすると、他のトランザクションの検索や更新をブロックして、ロックが解除されるまで待機させることができます。
SELECT ~ FOR UPDATE / UPDATE / DELETE は、対象となる行を排他ロックします。
SELECT ~ LOCK IN SHARE MODE は、対象となる行を共有ロックします(MySQL では SELECT ~ FOR SHARE)。
SELECT ~ LOCK IN SHARE MODE した行に SELECT ~ LOCK IN SHARE MODE しても待機しません。
(共有・排他)ロックがかかっている行に、(共有・排他)ロックをかけようとすると、
先にロックをかけたトランザクションが終わるまで待機します。
まとめると次のようになります。〇:待機しない
ロックすると、他のトランザクションの検索や更新をブロックして、ロックが解除されるまで待機させることができます。
SELECT ~ FOR UPDATE / UPDATE / DELETE は、対象となる行を排他ロックします。
SELECT ~ LOCK IN SHARE MODE は、対象となる行を共有ロックします(MySQL では SELECT ~ FOR SHARE)。
SELECT ~ LOCK IN SHARE MODE した行に SELECT ~ LOCK IN SHARE MODE しても待機しません。
(共有・排他)ロックがかかっている行に、(共有・排他)ロックをかけようとすると、
先にロックをかけたトランザクションが終わるまで待機します。
まとめると次のようになります。〇:待機しない
コマンド
通常のSELECT 共有ロック 排他ロック
--------------------------
共有ロック 待機
排他ロック 待機 待機2. テストデータの作成
DB の作成
テーブルの作成
テストデータの作成
コマンド
CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
テーブルの作成
コマンド
CREATE TABLE products (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
price INTEGER,
stock INTEGER DEFAULT 0,
PRIMARY KEY (id)
);
テストデータの作成
コマンド
INSERT INTO products (id, name, price, stock) VALUES (1, 'A', 1000, 10), (2, 'B', 2000, 20), (3, 'C', 3000, 30);
データ
+----+------+-------+-------+
| id | name | price | stock |
+----+------+-------+-------+
| 1 | A | 1000 | 10 |
| 2 | B | 2000 | 20 |
| 3 | C | 3000 | 30 |
+----+------+-------+-------+3. 動作確認
3.1 排他ロックされた行とは異なる行を排他ロック → 待機しない
AとBは異なるトランザクション
コマンド
A:BEGIN;
B:BEGIN;
A:SELECT * FROM products where id = 1 FOR UPDATE; # 排他ロック
B:SELECT * FROM products where id = 2 FOR UPDATE; # 待機しない
A:COMMIT;
B:COMMIT;3.2 排他ロックされた行と同じ行を排他ロック → 待機する
コマンド
A:BEGIN;
B:BEGIN;
A:SELECT * FROM products where id = 1 FOR UPDATE; # 排他ロック
B:SELECT * FROM products where id = 1 FOR UPDATE; # Aのトランザクションが終わるまで待機
A:COMMIT;
B:COMMIT;3.3 排他ロックされた行と同じ行に対して通常の SELECT → 待機しない
コマンド
A:BEGIN;
B:BEGIN;
A:SELECT * FROM products where id = 1 FOR UPDATE;
B:SELECT * FROM products where id = 1; # 待機しない
A:COMMIT;
B:COMMIT;3.4 UPDATE で排他ロックされた行と同じ行を排他ロック → 待機
コマンド
A:BEGIN;
B:BEGIN;
A:UPDATE products SET stock = stock - 1 where id = 1;
B:SELECT * FROM products where id = 1 FOR UPDATE; # Aのトランザクションが終わるまで待機
A:COMMIT;
B:COMMIT;3.5 UPDATE で排他ロックされた行に対して通常の SELECT → 待機しない
コマンド
A:BEGIN;
B:BEGIN;
A:UPDATE products SET stock = stock - 1 where id = 1;
B:SELECT * FROM products where id = 1; # 待機しない
A:COMMIT;
B:COMMIT;4. 注意事項
WHERE で条件を指定しなかったり、インデックスが効かずにフルスキャンになった場合、全ての行がロックされる可能性があります。

