トランザクション処理

目次

トランザクション処理

トランザクション処理は、DBMS(データベース管理システム)における重要な機能の1つで、複数の操作をまとめて一つの処理単位として実行する仕組みです。

トランザクションは、一連の処理のうち、1つでも失敗すると全て失敗となり、全てが成功するまで変更が反映されないため、データ整合性を維持することができます。

具体的な例を挙げると、銀行口座からの振込処理があります。以下にその例を示します。

例えば、Aさんの銀行口座からBさんの銀行口座に1万円の振込を行う場合を考えます。この場合、以下のような処理が行われます。

  1. Aさんの口座から1万円引き落とす。
  2. Bさんの口座に1万円振り込む。

このような処理が行われた場合、もし途中でエラーが発生した場合、Aさんの口座からお金が引き落とされたのに、Bさんの口座にお金が振り込まれていないという状態になってしまいます。

このような状態を防ぐために、トランザクション処理を行います。具体的には、以下のように処理をまとめます。

  1. Aさんの口座から1万円引き落とす。
  2. Bさんの口座に1万円振り込む。
  3. 1と2両方の処理が正常に完了した場合は、更新を確定(コミットと言います)する。
  4. 1と2どちらかの処理が途中で失敗した場合は、更新をロールバック(トランザクション開始直前の状態まで戻すこと)する。

このようにトランザクション処理を行うことで、途中でエラーが発生した場合でも、処理前の状態に自動的に戻されます。つまり、Aさんの口座からの引き落としは取り消され、Bさんの口座に振り込まれることはありません。

また、処理が成功した場合には、更新を確定(コミット)することで、データ整合性を維持することができます。

コミット

コミット(commit)とは、一連の変更やトランザクションを恒久的にデータベースに保存するプロセスです。

コミットを行うことで、トランザクション中に行われたすべての変更が確定し、データベースに反映されます。これにより、データの整合性が保たれ、システムやプログラムが予期せぬ中断を経験した場合でも、実行されたトランザクションの結果が失われることがありません。

コミットの対義語は後述する「ロールバック」で、これはトランザクション中に行われた変更をすべて取り消し、データベースをトランザクション開始前の状態に戻す操作です。コミットとロールバックの概念は、データベース管理におけるデータの整合性と安全性を保つために重要です。

排他制御

排他制御(exclusive control)は、DBMSに備わる重要な機能の1つで、同時に複数のユーザーやプログラムがデータベースにアクセスする際に、データの整合性を保つための仕組みです。

排他制御は、一つのトランザクションがあるデータ項目にアクセスしている間、他のトランザクションがそのデータ項目を変更できないように、データへのアクセスを制御します。

例として、航空会社の座席予約システムを考えましょう。同じ便の同じ座席に、同時に複数のユーザーが予約しようとするケースが想定されます。

  1. ユーザーAが便Xの座席Yを予約しようとします。
  2. 同時に、ユーザーBも便Xの座席Yを予約しようとします。

この場合、排他制御が適切に行われていないと、同じ座席が2人のユーザーに予約されることになり、データの整合性が失われてしまいます。排他制御を実施することで、この問題を防ぐことができます。

排他制御では、以下の手順でデータへのアクセスが制御されます。

  1. ユーザーAが便Xの座席Yを予約しようとする際、システムは座席Yにロックをかけます。ロックとは、複数のトランザクションが同一のデータにアクセスすることを制限することを指します。これにより、他のユーザーは一時的に座席Yへのアクセスができなくなります。
  2. ユーザーAの予約処理が完了すると、システムは座席Yのロックを解除します。
  3. ロックが解除された後、ユーザーBが座席Yを予約しようとすると、既に予約済みであることが分かり、別の座席を選択するように案内されます。

このように、排他制御を適切に行うことで、データの整合性が保たれ、複数のユーザーやプログラムが同時にデータベースにアクセスしても問題が発生しなくなります。

デッドロック

デッドロックは、複数のトランザクションが互いに相手の処理が完了するのを無限に待ち続ける状態を指します。

データベースのトランザクション処理において、ロックを用いることで整合性が保たれますが、これがデッドロックを引き起こす原因になることがあります。

例として、銀行の送金システムを考えましょう。2人の顧客AとBが、それぞれ他方の口座へ送金しようとしているケースを想定します。

  1. 顧客Aが自分の口座(口座1)から顧客Bの口座(口座2)へ送金しようとし、口座1にロックをかけます。
  2. 同時に、顧客Bが自分の口座(口座2)から顧客Aの口座(口座1)へ送金しようとし、口座2にロックをかけます。
  3. 続いて顧客Aは送金処理を完了させるために、口座2へのアクセスを試みますが、口座2は顧客Bによってロックされています。
  4. 同様に、顧客Bは送金処理を完了させるために、口座1へのアクセスを試みますが、口座1は顧客Aによってロックされています。

この状態で、どちらの顧客も他方のロックが解除されるのを待ち続けることになり、デッドロックが発生し、関連するトランザクションが停止してしまいます。

デッドロックを防ぐためには、以下のような対策が考えられます。

  • ロック順序: リソースに対するロックを一定の順序で行う。つまり、上記例では、両者ともに口座番号の低い口座1からロックするようにします。そうすれば、顧客A、顧客Bのどちらが先であれ、口座1のロックが解除されるまで待つことになり、同時に互いの口座へロックをかけようとする状況を防ぐことができます。
  • 閾値ロック: 一定数以上のリソースをロックする場合は、全てのリソースを同時にロックし、必要なリソースが確保できた場合のみ処理を実行する。これはデッドロックが口座にアクセス(ロック)する際の時間差によって生じているためです。
  • タイムアウト設定: 一定時間内にロックが解除されない場合、強制的にロックを解除し、処理をやり直すようにする(ロールバック)。

これらの対策を適切に実装することで、デッドロックのリスクを軽減することができます。

デッドロックの例え話

デッドロックを例え話で説明します。

すれ違うことができないような細い道を車で移動して、A、Bという二箇所を巡る場合、A→B、B→Aと自由に移動できてしまうと、途中ですれ違うことができない状況が発生します。

Aに向かう人はB方向にいる人が移動するのを待ち、Bに向かう人はA方向にいる人が移動するのを待ち続ける状況が発生してしまいます。

この状況を解決するには、いくつか方法があります。

  • 一方通行にする: A→Bだけのように一方通行にすることで、車はスムーズに移動できるようになります。仮に前の車が遅かったとしても、待っていればいずれ移動することができます。(ロック順序の例え)
  • 信号機を設置する: 道に信号機を設置し、AB間を一度に1台の車のみ通行できるように制限します。これにより、車がすれ違うことなく、順番に進むことができます。(閾値ロックの例え)
  • タイムアウト設定をする: 一定時間内にすれ違えない状況が発生した場合、自動的に車が後退するか、別のルートを探すようにします。これにより、長時間の待機が避けられ、スムーズな交通が保たれます。(タイムアウト設定の例え)

データベースの障害回復

データベースに障害が発生すると、データへのアクセスができなくなり、場合によってはデータが破損し、正確な情報の取得が困難になることがあります。

このような状況を解決するためには、データベース管理システム(DBMS)を活用して、バックアップファイルやログファイルから障害発生前のデータを復旧することが必要です。

DBMSには、障害時のデータ復旧機能が備わっており、これによって障害発生前の状態にデータベースを戻すことが可能です。

障害が長期間にわたる場合、業務に大きな影響を及ぼす可能性があるため、迅速かつ適切な復旧処理が重要です。

データベースのバックアップ

バックアップファイルとログファイルは、データベースの管理において重要な要素です。

バックアップファイル

データベースのバックアップファイルは、データベースの内容を一定時点で保存したファイルのことを指します。

これは、データベースが何らかの理由で損壊したり、データが失われたりした場合に、バックアップ時点の状態に復元するために使用されます。

バックアップの頻度や形式(フルバックアップ、差分バックアップ、増分バックアップなど)は、データベースのサイズや更新頻度、企業のポリシーなどにより異なります。

ログファイル

データベースのログファイルは、データベースに対するすべての操作(データの追加、更新、削除など)を時系列で記録したファイルです。

これは、システム障害やデータベースの損壊などが発生した際に、問題の発生源を特定したり、障害発生後のデータを復元したりするために使用されます。

ログファイルは通常、トランザクションログやエラーログなど、種類により分けられて保存されます。

データベースの障害回復方法

データベースの障害回復方法には、ロールフォワードとロールバックがあります。

ロールフォワード

ロールフォワードは、データベースを特定の時間点まで進めるための操作です。

これは通常、バックアップデータからデータベースを復元した後に行われます。

バックアップが作成された以降のすべてのトランザクション(データの変更)がログファイルに記録されているので、そのログファイルを使ってバックアップ以降の変更を再適用(ロールフォワード)します。

これにより、バックアップ作成時点から現在までのデータベースの状態を再現することができます。

ロールバック

ロールバックは、未完了またはエラーが発生したトランザクションによるデータベースの変更を取り消すための操作です。

ロールバックが必要になった場合、データベース管理システムはログファイルを利用して、トランザクションの変更を逆順に戻します。

これは、データベースに対する各トランザクションが、完全に成功するか、あるいは何も変更を残さずに失敗する(すべての変更をロールバックする)かのいずれかでなければならないという原則(後述するACID特性の一つ)に従っています。

したがって、トランザクションが途中で失敗した場合や、データの整合性に問題が発生した場合には、そのトランザクションによるすべての変更をロールバックし、トランザクション開始直前の状態に戻すことで、データベースの整合性を保ちます。

ACID特性

ACID特性とは、データベースのトランザクション処理が持つべき4つの重要な特性を指します。

ACIDは以下の頭文字を取っています。

原子性 (Atomicity)

トランザクション内の全操作が完全に成功するか、一つも実行されないかのどちらかを保証します。操作の一部だけが実行されることはありません。失敗した場合は、トランザクション開始前の状態に戻ります。

これにより、データの一貫性が維持されます。

例:銀行口座での送金処理
送金処理では、送金元の口座から金額を引き出し、送金先の口座に金額を入金するという2つの操作が必要です。

原子性が保たれているデータベースでは、両方の操作が成功するか、失敗するかのどちらか一方が保証されます。(失敗した場合はロールバックにより送金処理を行う直前の状態に戻ることが保証されます。)

これにより、送金処理が途中で失敗しても、送金元の口座だけからお金が消失したり、二重に引き出されたりすることがなくなります。

一貫性 (Consistency)

トランザクションの実行前後でデータベースの一貫性が保たれることを保証します。これは、トランザクションがデータベースのすべての制約(例えば、外部キー制約)を守り、正しい状態を維持することを意味します。

一貫性があると、データの整合性が保たれ、誤った情報や矛盾した情報が発生するのを防ぎます。一貫性がないと、データが信頼できなくなり、それに基づく判断や操作が誤った結果を生じる恐れがあります。

例:図書館のシステム
図書館のデータベースでは、各本の在庫状況と借りている人の情報を管理します。

一貫性が保たれているデータベースでは、ある本が借りられたとき、その本の在庫数が正しく減り、同時にその本を借りた人の情報も記録されます。

もし、この一貫性が保たれなかった場合、同じ本を複数の人が同時に借りることができたり、在庫数がマイナスになるなどの問題が発生する可能性があります。

独立性 (Isolation)

同時に実行される複数のトランザクションが互いに干渉しないようにすることを保証します。これにより、他のトランザクションの途中経過などの影響を受けず、各トランザクションが正確に実行されます。

例:オンラインショッピングでの同時注文
複数のユーザーが同時に限定品を注文しようとした場合、独立性が保たれているデータベースでは、各ユーザーの注文処理が他のユーザーの注文処理に影響を与えません。

つまり、複数のトランザクションを同時に実行しても互いに干渉せず、正確に在庫を減らし、順番で処理した時と同様に先着順で処理されます。

永続性 (Durability)

トランザクションが一度完了すると、その結果はシステムの障害が発生しても失われることがないことを保証します。つまり、データベースにコミットされた変更は恒久的に保存されます。

例:データの永続性
ユーザーがSNSに投稿をした場合、その投稿データはデータベースに永続的に保存されます。

耐久性が保たれているデータベースでは、システム障害が発生しても、投稿済みのデータは失われず、復旧後も閲覧可能です。

これらのACID特性を満たすことで、データベースはデータの整合性や信頼性を維持し、アプリケーションの正確な動作をサポートします。

関連用語

レプリケーション

レプリケーションとは、DBMSにおいて、あるサーバのデータを他のサーバに複製し、同期をとることで、可用性や性能の向上を図る手法のことを指します。つまり、元のデータベース(マスター)とそのコピー(レプリカ)が存在します。

レプリケーションには主に次のような目的があります:

  1. 可用性の向上: レプリケーションにより、一つのサーバーがダウンした場合でもデータベースへのアクセスを継続できます。これにより、システムのダウンタイムを軽減し、データベースの可用性を高めます。
  2. パフォーマンスの向上: 複数のレプリカからデータを読み出すことで、読み取りクエリのパフォーマンスを向上させることができます。
  3. バックアップ: レプリケーションは、データを複数の場所に分散させることでデータの損失リスクを減らす有効な手段でもあります。
分散型データベース

分散型データベースとは、物理的に異なる場所に存在する複数のサーバにデータが格納されているものの、ユーザーから見れば一つの統合されたデータベースとして機能するシステムのことを指します。

つまり、データベースが複数の場所に分散されていても、それら全てをまるで一つのデータベースであるかのように扱うことができます。これにより、大規模なデータを効率的に管理したり、地理的に広範囲にわたるアクセスを高速化したりすることが可能になります。

分散型データベースでは、「2相コミット(two-phase commit)」というプロトコルが重要な役割を果たします。これは、トランザクションが分散データベース全体で一貫性を保つための手法で、全ての参加ノードが同じ結果(コミットまたはロールバック)に達することを保証します。

2相コミットは主に以下の2つのフェーズから成ります。

  1. コミット要求フェーズ: トランザクションコーディネータ(通常はトランザクションを開始したノード)が、参加ノードに対してトランザクションのコミット準備ができているかを問い合わせます。
  2. コミットフェーズ: 全てのノードがコミット可能であると応答した場合、コーディネータは全ノードに対してトランザクションのコミットを指示します。一方で、一つでもノードがコミット不可能であると応答した場合は、全ノードにロールバックを指示します。

この2相コミットプロトコルにより、分散データベース全体でのデータ一貫性が確保されます。

目次