排他制御とは 楽観ロックと悲観ロックの違い・分離レベルとデッドロック対策
2026年9月14日
最終更新日:2026年10月23日
著者:株式会社ネクストスケール編集部
監修者:石丸真平

「2人が同時に同じ画面を編集したら、後から保存した内容だけが残ってしまった」「在庫が1個しかないのに、2件の注文が通った」。どちらも排他制御の設計が不十分なときに起きる典型的な事象です。
排他制御は、複数の処理が同じデータに同時にアクセスしても、矛盾が生じないように制御する仕組みです。ミューチュアルエクスクルージョン、相互排他とも呼ばれます。
厄介なのは、この種の不具合が通常のテストでは見つかりにくいことです。1人で操作している限り再現しません。稼働後、利用者が増えてから初めて表面化します。
この記事では、同時アクセスで起きる問題を整理したうえで、悲観ロックと楽観ロックの違い、分離レベル、デッドロックの対策、そして設計時の判断基準までを順に扱います。
| 確認したいポイント | 結論 | 詳細 |
| 排他制御とは? | 同時更新による不整合を防ぐ仕組み | 複数の処理が同じデータに同時にアクセスしても、矛盾が起きないよう制御することです。 |
| 方式は? | 悲観ロックと楽観ロックの2つ | 先にロックをかけるか、更新時に変化を検出するかの違いです。競合の頻度で選びます。 |
| どちらを選ぶ? | 競合が多ければ悲観、少なければ楽観 | 在庫や座席のように競合が頻発するなら悲観、通常の業務データなら楽観が基本です。 |
| 注意すべき点は? | デッドロックの発生 | 互いに相手の解放を待って処理が止まります。アクセス順序を統一するのが基本の対策です。 |
この記事でわかること
- 排他制御が必要な理由と、同時アクセスで実際に起きる4つの問題
- 悲観ロックと楽観ロックの違い、それぞれの実装方法と使い分けの基準
- 共有ロックと排他ロックの違い、ロックの粒度が性能に与える影響
- トランザクション分離レベルの4段階と、主要な製品の既定値
- デッドロックが起きる仕組みと、設計段階で打てる4つの対策
| システム開発とAI活用の進め方をまとめた資料を無料で配布しています 要件整理の進め方、開発の依頼範囲や体制の決め方、費用と期間の目安を1冊にまとめました。 社内での検討材料としてご活用いただけます。 > 資料請求はこちら ※オンライン完結/しつこい営業は一切いたしません |
排他制御とは
排他制御は、複数の処理が同じ資源に同時にアクセスする状況で、データの矛盾が生じないよう制御する仕組みです。対象となる資源は、データベースのレコード、ファイル、共有メモリなどです。
考え方は単純です。ある処理が資源を使っている間、他の処理からのアクセスを制限する。これにより、処理が直列に行われる状態を作ります。
実際に何が起きるのか
制御がない場合に起きる事象を、具体的に見ます。在庫数を1個減らす処理が同時に2件走った場合を考えます。
【制御がない場合】
処理A:在庫数を読む → 10
処理B:在庫数を読む → 10
処理A:10-1=9 を書く → 在庫 9
処理B:10-1=9 を書く → 在庫 9
本来なら 8 になるべきところが 9 のまま
2件出荷したのに、在庫は1個しか減っていません。この状態が積み重なると、帳簿と実在庫が合わなくなります。原因の特定も困難です。
同じことは、座席の予約、採番、ポイントの加算など、同時に処理されると困るあらゆる場面で起こります。
トランザクションとの関係
排他制御は、トランザクションと組み合わせて語られます。トランザクションは、複数の操作をひとまとまりとして扱う単位です。
トランザクションが満たすべき性質として、ACID特性と呼ばれる4つが定められています。
- 原子性(Atomicity):すべて実行されるか、まったく実行されないかのどちらか
- 一貫性(Consistency):実行の前後でデータの整合性が保たれる
- 独立性(Isolation):同時に実行されても互いに影響を与えない
- 永続性(Durability):完了した内容は障害が起きても失われない
このうち3つ目の独立性を実現する手段が、排他制御です。ロックをかけることで、他のトランザクションの影響を受けない状態を作ります。
設計を誤ると障害につながる
この領域の不備は、稼働後に発覚することが多いという特徴があります。1人での操作では再現せず、利用者が増えてから問題になります。
IPA(情報処理推進機構)は重要インフラ分野のシステム障害への対策の取り組みとして、報道された情報システムの障害情報を蓄積し、そこから得られた教訓を分野を越えて共有することで類似障害の再発防止につなげる活動を進めています。
設計段階で検討しておくべき事項であり、後から対応するのは容易ではありません。データ構造にまで影響するためです。
同時アクセスで起きる4つの問題
問題は4種類に分類されています。それぞれ原因と対策が異なるため、区別して理解します。
更新の喪失(ロストアップデート)
前章で示した在庫の例がこれにあたります。2つの更新が競合し、一方の更新が消えてしまう現象です。
業務システムで最も影響が大きい問題です。データが失われるため、後から気づいても復元できません。「更新したはずの内容が消えている」という問い合わせにつながります。
対策は、悲観ロックまたは楽観ロックです。4つの問題のうち、これだけは分離レベルの設定だけでは防げないため、明示的な対策が必要になります。
ダーティリード
他のトランザクションが確定していない変更を読んでしまう現象です。
処理Aが金額を修正したものの、まだ確定していない。その状態を処理Bが読み取って集計に使う。その後、処理Aが取り消された。この場合、処理Bは存在しなかった値で計算したことになります。
通常のデータベースでは、既定の設定で防がれています。あえて最も緩い分離レベルを選ばなければ発生しません。
反復不能読み取り(ノンリピータブルリード)
同じトランザクション内で同じデータを2回読んだのに、値が違っているという現象です。
1回目に読んだ後、別のトランザクションが値を変更して確定した。2回目に読むと変更後の値が見える。同一処理内で前提が変わってしまうため、計算結果が矛盾することがあります。
帳票の出力や集計処理で問題になります。合計と内訳が合わないという事象は、この原因で起こることがあります。
ファントムリード
同じ条件で検索したのに、2回目には存在しなかった行が現れる現象です。幻のように行が出現することからこの名前が付いています。
1回目の検索後、別のトランザクションが条件に合う行を追加して確定した。2回目の検索では、その行が結果に含まれます。件数が変わるため、処理の整合性が崩れます。
4つの中で最も防ぐのが難しい問題です。防ぐには最も厳しい分離レベルが必要になり、その分だけ性能への影響も大きくなります。
悲観ロックと楽観ロック
更新の喪失を防ぐ方式は2つです。「競合が頻繁に起きる」と想定するか、「めったに起きない」と想定するかの違いから、それぞれの名前が付いています。
悲観ロック|先にロックをかける
データを読み取る時点でロックをかけ、他の処理からのアクセスを禁止する方式です。競合が頻繁に起きる前提に立つため「悲観」と呼ばれます。
データベースでは、SELECT文にFOR UPDATEを付けることで実現します。ロックは、トランザクションが確定または取り消されるまで保持されます。
BEGIN;
SELECT zaiko FROM shohin WHERE id = 100 FOR UPDATE;
— ここで他のトランザクションは待たされる
UPDATE shohin SET zaiko = zaiko – 1 WHERE id = 100;
COMMIT;
利点は確実性です。ロックを取得できた処理だけが更新できるため、更新の喪失は原理的に起こりません。
難点は待ち時間の発生です。ロックが解放されるまで他の処理は進めません。ロックを長時間保持すると、システム全体の応答が悪化します。
楽観ロック|更新時に変化を検出する
データそのものにはロックをかけず、更新する時点で「読み取ったときと同じ状態か」を確認する方式です。競合はめったに起きない前提に立つため「楽観」と呼ばれます。
一般的な実装は、テーブルにバージョン番号の列を持たせる方法です。読み取り時のバージョンを保持しておき、更新時に一致するかを確認します。
— 読み取り時:version = 5 を取得しておく
UPDATE shohin
SET zaiko = 8, version = 6
WHERE id = 100 AND version = 5;
— 更新件数が 0 なら、他の処理が先に更新している
更新件数が0件だった場合、競合が起きたと判断します。そのときはエラーとして利用者に通知し、再取得してやり直してもらいます。
利点は待ち時間がないことです。ロックをかけないため、他の処理を妨げません。難点は、競合が起きたときに作業がやり直しになることです。
バージョン番号の代わりに最終更新日時を使う実装もあります。ただし、同一時刻に更新が重なる可能性があるため、バージョン番号を使うほうが確実です。
使い分けの基準
判断軸は明確です。競合の頻度と、やり直しの負担の大きさで決まります。
- 悲観ロックが向く:競合が頻繁に起きる、やり直しの負担が重い、確実性が最優先
- 楽観ロックが向く:競合がまれ、多数の利用者が同時にアクセスする、待たせたくない
実務では、在庫の引き当て、座席の予約、採番処理は悲観ロック、通常の業務データの編集画面は楽観ロックという使い分けが一般的です。
同じシステム内で両方を使い分けて構いません。処理の性質に応じて選ぶのが正しい設計です。全体を一律に決めようとすると、どちらかで不都合が出ます。
よくある実装の誤り
方式を選んでも、実装を誤ると意味がありません。頻出する誤りを3つ挙げます。
1つ目は、楽観ロックで更新件数を確認していないケースです。バージョンを条件に含めても、更新件数が0件だったことを検知しなければ、競合は黙って無視されます。エラーとして扱う処理が必要です。
2つ目は、悲観ロックの範囲が広すぎるケースです。処理の冒頭でロックを取得し、最後まで保持する実装にすると、待ち時間が長くなります。更新の直前に取得するのが原則です。
3つ目は、アプリケーション側でのみ判定しているケースです。「読み取った値と現在の値を比較する」という処理をプログラム内で書いても、その比較と更新の間に別の処理が割り込む余地が残ります。データベースの機能で保証する必要があります。
| 設計方針や非機能要件の整理からご相談いただけます 仕組みは分かっても、自社の業務でどう設計すべきかは別の問題です。 要件の整理からご一緒する30分の無料相談をご用意しています。 ▶ 相談予約はこちら ※オンライン完結/秘密厳守/助成金活用のご相談も歓迎 |
ロックの種類と粒度
ロックは1種類ではありません。何を許し何を禁じるか、そしてどの範囲にかけるかで分かれます。
共有ロックと排他ロック
2つの基本的な種類があります。読み取りを許すかどうかが違いです。
- 共有ロック(Sロック):読み取りのためのロック。他からの読み取りは許可、更新は禁止
- 排他ロック(Xロック):更新のためのロック。他からの読み取りも更新も禁止
共有ロックは複数同時に取得できます。複数の処理が同じデータを同時に読むことは問題ないためです。一方、排他ロックは1つだけです。
共有ロック中 排他ロック中
共有ロック要求 取得可 待機
排他ロック要求 待機 待機
この対応関係を理解しておくと、なぜ処理が待たされているのかを判断できます。読み取りだけの処理が待たされている場合、どこかで排他ロックが保持されています。
ロックの粒度
どの範囲にロックをかけるかという選択です。範囲が広いほど安全だが、同時に処理できる量は減ります。
- 行ロック:1件のレコードだけをロック。最も細かく、同時実行性が高い
- ページロック:データが格納されている単位でロック
- テーブルロック:テーブル全体をロック。他の処理は一切入れない
通常は行ロックが使われます。多くのデータベース製品が既定でこの単位を採用しています。
ただし、ロックする行数が多くなると、製品が自動的にテーブルロックへ切り替えることがあります。これをロックエスカレーションと呼びます。想定外に処理が待たされる原因になります。
粒度が性能に与える影響
粒度の選択は、性能要件と直結します。細かくすれば同時実行性は上がりますが、管理のための負荷が増えます。
大量のデータを一括更新するバッチ処理では、行ロックを大量に取得するより、テーブルロックをかけたほうが速い場合もあります。処理の性質による判断です。
IPAが公開する非機能要求グレードでは、可用性、性能・拡張性、運用・保守性など6つの大項目について要求レベルを段階的に整理する枠組みが提供されています。同時利用者数や応答時間の要件を先に定めてから、排他制御の設計に入るのが正しい順序です。要件の書き方は要件定義の例|システム種類別の要件例と、機能要件・非機能要件の書き換え集も参考になります。
トランザクション分離レベル
ロックを個別にかけるのではなく、データベース全体の振る舞いとして設定する方法です。第2章で挙げた問題のうち、どこまでを防ぐかを選びます。
4つのレベル
標準として4段階が定められています。上から下へ、安全性が高くなり、同時実行性が下がります。
ダーティ 反復不能 ファントム
READ UNCOMMITTED 発生 発生 発生
READ COMMITTED 防止 発生 発生
REPEATABLE READ 防止 防止 発生
SERIALIZABLE 防止 防止 防止
READ UNCOMMITTEDは実務でほぼ使いません。確定していないデータを読めてしまうため、正確性が求められる業務には適しません。
注意すべきは、更新の喪失がこの表に含まれていないという点です。分離レベルを上げても、悲観ロックや楽観ロックによる対策は別途必要になります。
製品ごとの既定値
既定の分離レベルは製品によって異なります。移行や併用の際に挙動が変わる原因になるため、確認しておきます。
一般に、SQL ServerとPostgreSQLはREAD COMMITTED、MySQLのInnoDBはREPEATABLE READが既定とされています。Oracleも読み取り一貫性を前提とした動作です。
同じSQLでも、製品が違えば結果が変わる可能性があります。正確な既定値と挙動は、利用する製品の公式ドキュメントで確認してください。同名のレベルでも実装に差があることが知られています。
どのレベルを選ぶか
基本は既定値のまま使います。これで多くの業務要件は満たせます。
個別に厳しくする必要がある処理だけ、トランザクション単位でレベルを指定します。全体をSERIALIZABLEにすると、性能が大きく低下します。
「安全だから最も厳しいレベルにする」という判断は避けます。同時実行性が落ち、待ち時間やデッドロックが増えます。必要な箇所だけを厳しくするのが原則です。
デッドロックとその対策
排他制御を導入すると、新たに発生しうる問題があります。それがデッドロックです。
デッドロックが起きる仕組み
2つ以上のトランザクションが、互いに相手が保持しているロックの解放を待ち続ける状態です。どちらも進めなくなります。
処理A:商品テーブルをロック → 次に顧客テーブルを要求
処理B:顧客テーブルをロック → 次に商品テーブルを要求
→ AはBの解放を待ち、BはAの解放を待つ(永久に進まない)
多くのデータベース製品は、デッドロックを検知して一方を強制的に取り消します。取り消された側はエラーになり、処理が失敗します。
つまり、システムは停止しませんが、利用者にはエラーとして見えます。頻発すれば業務が止まります。
4つの対策
設計段階で打てる対策があります。効果の大きい順に挙げます。
- アクセス順序を統一する:複数テーブルを扱う際、常に同じ順序でロックを取得する
- トランザクションを短くする:ロックの保持時間を最小化する
- ロックの範囲を絞る:必要な行だけをロックし、テーブル全体は避ける
- タイムアウトを設定する:待ち時間の上限を定め、超えたらエラーにする
1つ目が最も効果的です。「商品テーブル、顧客テーブル、受注テーブルの順にアクセスする」といったルールを決め、全処理で守れば、デッドロックは原理的に起きにくくなります。
2つ目も重要です。トランザクションの中に利用者の入力待ちや外部システムへの通信を含めると、ロックが長時間保持されます。これは避けるべき設計です。
発生したときの調査
デッドロックのログを確認できる状態にしておきます。多くの製品は、発生時にどのトランザクションがどのロックを待っていたかを記録します。
ログから、関与した処理とアクセス順序を特定できます。順序を揃えるだけで解消するケースが大半です。
再現が難しい場合は、意図的に同時アクセスを発生させるテストを行います。負荷試験のシナリオに、競合が起きる操作を含めておくのが確実な方法です。
設計時の判断基準
方式の選択は、技術ではなく業務の性質で決まります。判断の順序を整理します。
まず競合の頻度を見積もる
出発点はここです。そのデータに、複数人が同時にアクセスする可能性がどれだけあるかを確認します。
全社で1件しかない在庫データを、10人の営業が同時に引き当てる。これは競合が頻発します。一方、各担当者が自分の顧客情報だけを編集するなら、競合はまず起きません。
競合しないデータに悲観ロックをかけても、待ち時間だけが増えます。過剰な制御は性能を落とすだけで、安全性には寄与しません。
業務への影響で方式を選ぶ
競合が起きたときに、どちらの結果が業務上望ましいかを考えます。
在庫の引き当てなら、待たせてでも正確に処理すべきです。悲観ロックが適します。長文を編集する画面なら、待たせるより「他の人が更新しました」と伝えて再編集させるほうが実用的です。楽観ロックが適します。
この判断は業務部門と一緒に行います。技術者だけで決めると、運用に合わない設計になります。
既存システムを改修する場合
後から排他制御を追加するのは、新規に設計するより難しくなります。データ構造の変更が必要になることが多いためです。
楽観ロックを導入するにはバージョン番号の列が必要です。既存テーブルへの列追加は、参照している全処理への影響を確認する作業を伴います。
現実的な進め方は、影響の大きい処理から順に対応することです。在庫や金額のように不整合の影響が大きいデータを先に対策し、影響の小さい部分は後回しにします。全面的な改修を待つより、被害を減らせます。
データベース以外の排他制御
対象はデータベースだけではありません。ファイル、バッチ処理、外部システムとの連携でも同じ考え方が必要になります。
同じバッチが二重に起動しないようにする、ファイルを処理中に別の処理が読まないようにする、外部システムへの送信が重複しないようにする。いずれも排他制御の一種です。
実装方法は、ロック用のテーブルを設ける、ロックファイルを作る、処理状態を管理するフラグを持つなどです。データベースのロック機能に頼れない場面では、自分で仕組みを作ります。
画面と業務の設計で配慮すること
技術的に正しく動くことと、利用者が困らないことは別です。運用面での配慮を整理します。
利用者に何を見せるか
楽観ロックで競合が検出されたとき、「エラーが発生しました」だけでは利用者は対応できません。
「他の利用者が先に更新しました。最新の内容を確認して、再度入力してください」と伝えます。可能であれば、誰がいつ更新したかも表示します。
入力した内容を失わせない配慮も重要です。長文を入力した後にエラーで消えると、利用者は強い不満を持ちます。入力内容を保持した状態で再表示する設計にします。
長時間の編集をどう扱うか
利用者が画面を開いたまま席を離れることは日常的に起こります。この間ロックを保持し続ける設計は避けます。
編集画面を開いた時点でロックする方式は、開いたまま放置されると他の人が永久に編集できなくなります。画面を開く操作でロックを取得しないのが原則です。
どうしても編集中を示したい場合は、データベースのロックではなく、業務上のフラグとして「編集中」を持たせ、一定時間で自動解除するという実装にします。強制解除の手段も用意します。
テストで確認すること
通常のテストでは発見できないため、意図的に同時アクセスを起こすテストが必要です。
2つのブラウザで同じデータを開き、片方で更新した後にもう片方で更新する。この操作で、想定どおりのメッセージが出るかを確認します。手作業でも実施できます。
大量の同時アクセスは負荷試験で確認します。競合が起きる操作をシナリオに含め、デッドロックやタイムアウトが発生しないかを見ます。テスト工程の設計はシステム開発の外注とは|メリット・デメリット、費用相場、外注先の種類と選び方でも触れています。
まとめ
排他制御は、複数の処理が同じデータに同時アクセスしても矛盾が生じないように制御する仕組みです。トランザクションのACID特性のうち、独立性を実現する手段にあたります。
同時アクセスで起きる問題は4種類です。更新の喪失だけは分離レベルの設定では防げず、悲観ロックか楽観ロックによる対策が必要になります。
方式の選択は、競合の頻度とやり直しの負担で決まります。在庫や座席のように競合が頻発するなら悲観ロック、通常の編集画面なら楽観ロックが基本です。同じシステム内で使い分けて構いません。
デッドロックへの最も効果的な対策は、複数テーブルへのアクセス順序を統一することです。あわせて、トランザクションに利用者の入力待ちを含めない設計にします。
まずは自社のシステムで、2つのブラウザから同じデータを同時に更新してみてください。後から保存した内容だけが残るなら、対策が入っていないというサインです。
AIコンサル・AX伴走支援サービスご紹介資料
この資料でこんなことがわかります!
- 社外AI役員とは
- 支援内容
- 導入の進め方
- 導入実績・効果
\3ステップで簡単入力/
| システム開発の進め方から、無料で相談できます 受け取った設計の妥当性を判断したい、社内に開発の知見がなく不安があるといった段階のご相談も承っています。 営業色は一切ありません。 ▶ 相談予約はこちら ※オンライン完結/秘密厳守/助成金活用のご相談も歓迎 |
この記事の監修者
株式会社ネクストスケール 代表取締役




