【図解】楽観ロックと悲観ロックの違い!仕組みや使い分けをわかりやすく解説!

データベースやWebアプリケーションを開発していると、「楽観ロック」や「悲観ロック」という言葉を耳にすることがあります。どちらも、複数の人が同じデータを同時に操作したときに、データの整合性(正しい状態)を保つための仕組みですが、その考え方はまったく異なります。

この記事では「楽観ロック」と「悲観ロック」について、以下の内容を図を用いてわかりやすく解説します。

  • そもそも排他制御とは?
  • 楽観ロックとは
    • 楽観ロックの仕組み
    • 楽観ロックのメリットとデメリット
  • 悲観ロックとは
    • 悲観ロックの仕組み
    • 悲観ロックのメリットとデメリット
  • 「楽観ロック」と「悲観ロック」の違い
  • 「楽観ロック・悲観ロック」と「共有ロック・占有ロック」の違い

そもそも排他制御とは?

排他制御は、複数のユーザーやプロセスが同じデータを同時に操作したときに、データの整合性(正しい状態)を保つための制御です。

たとえば、ショッピングサイトで「在庫が10個ある商品」をAさんとBさんの2人が同時に購入するケースを考えてみましょう。

まず、購入可能かどうか確認するために「在庫テーブル」から在庫数を取得します。残りの在庫数は「10個」なので、どちらも購入可能であることがわかります。

そもそも排他制御とは?01

購入可能なのでAさんとBさんが同時に購入します。それぞれ「在庫テーブル」の在庫を1つ減らす更新を行います(Aさんが「在庫数を10→9」に更新し、Bさんも「在庫数を10→9」に更新します)。すると、最後に更新した方(ここではBさんとする)のデータが上書きされてしまい、結果として在庫数は「9個」になってしまします。2人が購入しているため、本来は在庫数は「8個」になるはずなのに、データが不整合な状態になっています。

そもそも排他制御とは?02

このような、同時更新によるデータの不整合(上書き事故)を防ぐために行うのが「排他制御」です。

排他制御を行うことで、データの同時書き込みを制限したり更新の順番を制御したりすることで、データの整合性を保つことができます。

排他制御にはさまざまな方法がありますが、その中でも代表的なのが「楽観ロック」と「悲観ロック」です。まずは「楽観ロック」から解説します。

楽観ロックとは

楽観ロックは、「同時にデータを更新しても、たぶん大丈夫だろう」という“楽観的”な考え方に基づいた排他制御です。楽観ロックでは、データ自体はロックせず、更新対象のデータが更新前と同じであるかを確認してから更新することで、データの整合性を保ちます。

つまり、「競合が起きるのは稀だから、自由に更新して、最後に矛盾がないか確認しよう」という発想です。

楽観ロックは楽観的排他制御楽観的ロックとも呼ばれています。

楽観ロックの仕組み

ここでも同じく、「在庫が10個ある商品」をAさんとBさんの2人が同時に購入する場合を考えてみましょう。

まずは、購入可能であるかを確認するために「在庫テーブル」から在庫数を取得します。残りの在庫数は「10個」なので購入可能であることがわかります。ここでポイントなのは「在庫テーブル」にバージョン番号が付与されている点です。データを取得する際にそのバージョン番号も確認します。

楽観ロックの仕組み01

まず先にAさんが商品を購入したとします。その時「在庫テーブル」の在庫を1つ減らす更新を行います(Aさんが「在庫数を10→9」に更新します)。同時に「在庫テーブル」のバージョン番号も「1→2」にカウントアップします。次に商品の購入がやや遅れたBさんも、「在庫テーブル」の在庫を1つ減らす更新を行います。しかし、「Bさんが取得した時点のデータのバージョン番号(1)」と「更新時のバージョン番号(2)」が一致しないため、「他の人によって変更されている」と判断され、更新はエラー(楽観ロックエラー)になります。

楽観ロックの仕組み02

このように、楽観ロックは「データの変更を検知して更新を防ぐ」ことで、データの整合性を保ちます。

楽観ロックのメリットとデメリット

楽観ロックのメリットデメリットを以下に示します。

メリット

  • データをロックしないので、処理が順番待ちになることはない。ただし同時操作が行われた場合は、後負けになる
  • デッドロック(お互いのロック待ち)が発生しない
  • 実装が比較的シンプル(更新前のバージョン確認などで済む)

デメリット

  • 同時更新が起きると更新エラーが発生し、再試行が必要
  • 更新処理が多いシステムではエラーが頻発する可能性がある

楽観ロックはデータをロックしないため、同時更新が頻繁に発生しない環境で高いパフォーマンスを発揮します。そのため、読み取りが多く、更新が少ないシステム(例:閲覧中心のWebアプリ)に向いています。

悲観ロックとは

悲観ロックは、「他の人が同時に更新してくるかもしれない!」という“悲観的”な考え方に基づいた排他制御です。悲観ロックでは、データを更新する前にデータをロックし、他の処理が同じデータに触れないようにすることで、データの整合性を保ちます。

つまり、「競合は起きるものなので、競合が起こる前に、先にロックを取っておこう」という発想です。

悲観ロックは悲観的排他制御悲観的ロックとも呼ばれています。

悲観ロックの仕組み

ここでも同じく、「在庫が10個ある商品」をAさんとBさんの2人が同時に購入する場合を考えてみましょう。

まずアクセスがやや早かったAさんが「在庫テーブル」から在庫数を取得し、購入処理を開始します。このときAさんの処理では、「在庫テーブルのデータ」にロックをかけます。これにより、Aさんが購入処理を完了するまで、Bさんはその在庫テーブルを読み取りできません(データベースの設定によっては読み取りは可能だが更新ができない場合もあります)。

悲観ロックの仕組み01

Aさんの購入処理が完了すると「在庫テーブル」の在庫を1つ減らす更新を行います(Aさんが「在庫数を10→9」に更新します)。同時に、ロックを解除します。ロックが解除されたので、Bさんの処理がようやく進みます。Bさんは「在庫テーブル」から在庫数を取得し、購入処理を開始します。このとき、Bさんの処理でも、「在庫テーブルのデータ」にロックをかけます。

悲観ロックの仕組み02

このように、悲観ロックは「他の人の更新をブロックする」ことで、データの整合性を保つことができます。

悲観ロックのメリットとデメリット

悲観ロックのメリットデメリットを以下に示します。

メリット

  • 同時更新による競合を確実に防げる

デメリット

  • データをロックするため、他の処理が待ち状態になる(スループット低下)
  • デッドロック(お互いのロック待ち)が発生する可能性がある

悲観ロックは、更新が頻繁に行われる環境でも確実にデータの整合性を保てます。そのため、更新処理が多いシステムや、データの整合性を最優先するシステム(例:銀行・会計などの業務システム)に向いています。

「楽観ロック」と「悲観ロック」の違い

ここで、「楽観ロック」「悲観ロック」の違いを整理しましょう。

簡単に言うと、「データの確認(SELECT)→データの更新(UPDATE)」というフローがあるときに、「データの確認(SELECT)」の時点でロックをするのが「悲観ロック」ロックをせずに「データの更新(UPDATE)」の時点で整合性を確認するのが「楽観ロック」です。もちろん、どちらの場合もデータの更新時にはロックをかけます。

違いを表でまとめると以下のようになります。

比較項目楽観ロック
(楽観的排他制御)
悲観ロック
(悲観的排他制御)
考え方「同時更新はめったに起きないだろう」という楽観的な発想「他の人が更新してくるかもしれない」という悲観的な発想
制御の方法更新時にデータが変更されていないかを確認してから更新する更新前にデータをロックし、他の処理をブロックする
データのロックロックしないロックする
デッドロック発生しない発生する可能性がある
スループット高い(ロック待ちがない)低下しやすい(ロック待ちが発生)
競合時の動作後から更新した処理がエラー(更新失敗)になる他の処理をブロックして競合を防ぐ
実装の複雑さ比較的シンプル
(バージョン番号の確認など)
やや複雑
(ロック管理が必要)
向いているシステム読み取りが多く更新が少ないシステム
(例:閲覧中心のWebアプリ)
更新が多く整合性を重視するシステム
(例:銀行・会計システム)

「楽観ロック・悲観ロック」と「共有ロック・占有ロック」の違い

データベースには「楽観ロック・悲観ロック」「共有ロック・占有ロック」という2種類の異なる概念があります。

両者は名前が似ているため混同されがちですが、役割はまったく異なります。以下に違いをまとめます。

  • 楽観ロック・悲観ロック
    • 「どうやってロックを扱うか」という考え方
    • 楽観ロックと悲観ロックはデータの競合を「検知して対処するか」「事前に防ぐか」という違い
    • 楽観ロック
      • 「同時にデータを更新しても、たぶん大丈夫だろう」という“楽観的”な考え方に基づいている
      • データ自体はロックせず、更新対象のデータが更新前と同じであるかを確認してから更新する
      • 競合が発生した場合は、後から更新した処理がエラーになる
    • 悲観ロック
      • 「他の人が同時に更新してくるかもしれない!」という“悲観的”な考え方に基づいている
      • データを更新する前にデータをロックし、他の処理が同じデータに触れないようにする
      • 他のユーザーの更新をブロックすることで、確実に整合性を保つ
  • 共有ロック・占有ロック
    • 「どんな種類のロックを取るか」という技術的な仕組み
    • 共有ロックと占有ロックは、「どの程度まで他のユーザーの操作を許すか」の違い
    • 共有ロック
      • 複数ユーザーが同時に「読み取り」はできるが、「更新」はできない状態
      • 例:他の人がSELECTはできるが、UPDATEはできない状態
    • 占有ロック
      • 1人だけが「読み書き」できるけど、他の人は読み取りも含めてアクセスできない状態
      • 例:あるユーザーが更新処理中は、他の人はSELECTすらできない

本記事のまとめ

この記事では「楽観ロック」と「悲観ロック」について説明しました。

「楽観ロック」と「悲観ロック」はどちらもデータの整合性を守るための排他制御ですが、アプローチがまったく異なります。

楽観ロックは「競合はめったに起きない」と考え、更新時に矛盾を検知して防ぐ方法。読み取りが多いWebアプリなどで高いパフォーマンスを発揮します。

悲観ロックは「競合は起きるもの」と考え、あらかじめデータをロックして他の処理をブロックする方法。銀行や会計システムなど、整合性が最優先の場面で有効です。

また、これらとは別に「共有ロック・占有ロック」というデータベース内部のロック種別も存在します。名前が似ているため混同しやすいですが、「考え方の違い(楽観/悲観)」と「ロックの種類(共有/占有)」は別物であることを理解しておくことが重要です。

お読みいただきありがとうございました。

スポンサーリンク