今回は「MySQLにおける排他制御(Concurrency Control)とトランザクションの分離レベル」について、初学者でもわかるように、例えや表を交えて丁寧に解説していきます。
排他制御とは?その目的は?
複数の人(トランザクション)が同時に同じデータにアクセスしようとすると、思わぬバグやデータの矛盾が起きてしまうことがあります。
例えるなら、「ひとつのノートに、同時に別の人が書き込もうとする」状態です。
うまく調整しないと、メモが重なったり、消されたりしてしまいます。
そこで登場するのが排他制御です。
MySQLでの排他制御の方法
方法①:ロック(Lock)
ロックは「このデータ、今自分が使ってるよ!」と周囲に伝える仕組みです。
ロックの種類
| 種類 | 概要 | 他のトランザクションの影響 | 
|---|---|---|
| 共有ロック(Shared Lock) | データの読み取りを許可 | 書き込みはできない | 
| 排他ロック(Exclusive Lock) | 読み取り・書き込みを独占 | 他の読み書きをブロック | 
明示的なロックの例
START TRANSACTION;
SELECT * FROM items WHERE id = 1 FOR UPDATE;  -- 排他ロック
-- ここで更新処理などを行う
COMMIT;
FOR UPDATE を使うと、その行に対して他の更新をブロックできます。
方法②:トランザクションの分離レベル(Isolation Level)
4つの分離レベルと特徴
| レベル | Dirty Read | Non-Repeatable Read | Phantom Read | 同時実行性 | 
|---|---|---|---|---|
| READ UNCOMMITTED | あり | あり | あり | 高い | 
| READ COMMITTED | なし | あり | あり | やや高い | 
| REPEATABLE READ(デフォルト) | なし | なし | あり | 中程度 | 
| SERIALIZABLE | なし | なし | なし | 低い | 
- Dirty Read:他の未確定データを読んでしまう
 - Non-Repeatable Read:同じクエリ結果が2回で異なる
 - Phantom Read:検索条件を満たす行の数が変わる
 
設定方法
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
※ トランザクション開始前に設定してください!
デッドロックとは?
複数のトランザクションが、互いにロックを待ち合ってしまい、永久に進めない状態です。
例えるなら…
- Aさんがノート1を持ってノート2を待っている
 - Bさんがノート2を持ってノート1を待っている
→ どちらも譲らない、膠着状態になる 
MySQLはこの状態を検出して、自動的に**どちらかを強制終了(ROLLBACK)**させます。
対策:
- ロックの順序を統一する
 - トランザクションはできるだけ短く
 - 必要な行だけにロックをかける
 
実例:排他ロックでデータ競合を防ぐ
シナリオ
- テーブル:
inventory - カラム:
id,stock 
目的:在庫を更新する前にロックして他の人の更新を防ぐ
START TRANSACTION;
SELECT stock FROM inventory WHERE id = 1 FOR UPDATE;
-- 在庫数に応じた処理を行う
UPDATE inventory SET stock = stock - 1 WHERE id = 1;
COMMIT;
解説
FOR UPDATE:排他ロックをかけて他の更新をブロックCOMMIT:処理が完了したら確定
まとめ
| 項目 | 内容 | 
|---|---|
| 排他制御の目的 | 同時実行でもデータの整合性を保つ | 
| 方法1:ロック | 読み書きの競合を避ける | 
| 方法2:分離レベル | 読み取りの一貫性を保証 | 
| デフォルトの分離レベル | REPEATABLE READ(非反復読み取りを防止) | 
| デッドロック | ロックの待ち合い状態、MySQLが自動解決するが注意が必要 | 
今後の学習の指針
- 実際にトランザクションと
FOR UPDATEを使ってデモしてみよう - 分離レベルごとに、どんな問題が起きるかシミュレーションして比較
 SHOW ENGINE INNODB STATUSを使ってデッドロックの発生状況を確認してみよう- ORMやフレームワーク(JPA, MyBatis)での排他制御の書き方もチェックしよう
 
データベースの整合性を守る力=プロフェッショナルエンジニアの証です。
焦らず、順番にステップアップしていきましょう!