11. トランザクション
- 11.1. トランザクションの特性
- 11.2. コミットとロールバック
- 11.3. トランザクションの構文
- 11.4. 排他制御
- 11.5. ロック
- 11.6. トランザクションの定義
一般にデータベースには多くの人がアクセスし、様々な処理を行います。閲覧するだけの人もいれば、データを追加・更新したり、削除する人もいます。その中でも特に、データの追加・更新・削除、SQL 文で言うと「INSERT 文」「UPDATE 文」「DELETE 文」についての処理のまとまりをトランザクションと言います。
上記 3つのデータ操作文は、お互いに関連をもっていて、連続して実行されることにより、意味のある一つの単位を構成することが少なくありません。トランザクションとはこの一連の作業単位のことで、データの整合性を確保するため、またデータの障害復旧といった目的に利用されます。
11.1. トランザクションの特性
トランザクションは、次の 4つの特性を満たさなければなりません。これら 4つの特性は、それぞれの名前の頭文字をとって ACID 特性といいます。
- 原子性 (ATOMICITY)
- トランザクションは、それ以上分割することのできない最小の作業単位であるということです。このため、トランザクションを構成する処理の結果がすべて有効になるか、またはすべて無効になるかのいずれかであるということです。
例えば、あるトランザクションに処理 A と処理 B があるとします。処理 A と処理 B が正しく実行されたときは両方の処理結果が有効になります。しかし、処理 A だけ、または処理 B だけが正しく実行された場合は、両方の処理結果が無効になります。 - 一貫性 (CONSISTENCY)
- トランザクションで処理されるデータは、実行前と後でデータの整合性を持ち、一貫したデータを確保しなければなりません。
- 隔離性 (ISOLATION)
- 処理対象が同じデータである複数のトランザクションを一度に実行する場合は、それぞれのトランザクションは隔離された (独立された) 状態でデータの変更を行わなければなりません。
トランザクション A とトランザクション B がデータを共有している場合、トランザクション A で変更中のデータを、トランザクション B で処理することは認められないということです。トランザクション A が終了し、データが確定した後であればトランザクション B でデータを処理することができます。 - 持続性 (DURABILITY)
- トランザクションで処理されるデータの状態はトランザクションが終了するまで変化しないということです。トランザクションで処理を変更する SQL 文を実行しますが、トランザクションの最後で変更を確定するまでは実際のデータの変更は行われないということです。
これらのトランザクションの特性により、データベースへの同時アクセスを制御したり、障害発生時の処理を制御することができるようになります。それぞれ、例をあげて説明します。
同時アクセスの制御では、会議室の予約システムを例に説明します。総務部の AMI さんと人事部の YUMI さんがほぼ同時に同じ会議室を予約しようとしたときを想定します。次の図のように AMI さんも YUMI さんも自分のパソコンから会議室が開いていることを確認し (T1, T2)、それぞれが会議室を予約しようとしてデータベースに書き込んでしまう (T3, T4) と、同じ会議室に対して 2人が予約したことになってしまいます。このような場合、データに不整合が発生してしまうことになります。
トランザクションはこのような問題に対して、その特性である CONSISTENCY (一貫性) と ISOLATION (隔離性) により対処することができます。AMI さんのトランザクションは、会議室の状況を読み取った時点で開始され (T1)、予約情報を書き込んだ時点で終了します (T4)。この間、YUMI さんが予約しようとしても (T3)、データはロックされるため、予約情報を書き込むことはできません。その結果データの整合性が確保されます。
次に、障害発生時の処理の制御について、銀行の預金システムを考えてみます。ある会社が本社の口座から営業所の口座に、資金を移動しようとする場合を想定します。この場合に行う処理は、本社の口座の預金残高を減らすという処理と、営業所の口座の預金残高を増やすという処理を連続的に実行することです。ところが、本社の預金残高を減らす処理に成功した後で (T1)、なんらかの障害が発生し (T2)、営業所の預金残高を増やす処理に失敗すると (T3)、資金がなくなってしまうことになります。
トランザクションはこの問題に対して、ATOMICITY (原子性) と DURABILITY (持続性) の特性により対処できます。トランザクションが正常に終了した場合にのみデータベースに変更を反映し、途中で何らかの障害が発生した場合には反映しないようにすることによって、データの整合性を確保します。本社の預金残高を減らす処理と営業所の預金残高を増やす処理を一つのトランザクションにまとめます。そして、トランザクション全体が正常に終了した場合にのみ、変更処理の結果を口座データに反映するようにします。トランザクションは、本社の預金残高を減らした時点で開始され (T1)、営業所の預金残高を増やした時点で終了します (T3)。この間、なんらかの障害が発生し (T2)、営業所の預金残高を増やす処理に失敗した場合には、トランザクション全体が取り消されるため、本社の口座データに対する変更処理も反映されません。その結果、データの整合性が確保されます。
11.2. コミットとロールバック
トランザクションによるデータの変更処理が正常に終了した場合に、その変更処理を有効な結果と確定し、データベースに反映することをコミットといいます。また、トランザクションによるデータの変更処理の途中で何らかの障害が発生した場合に、それまでの変更処理を無効なものとし、トランザクションが実行される前の状態にもどすことをロールバックといいます。
このコミットとロールバックによりトランザクションの ACID 特性が生きているといえます。
11.3. トランザクションの構文
SQL92 では、「INSERT 文」「UPDATE 文」「DELETE 文」のいずれかのデータ操作文を実行した時点で、自動的にトランザクションが開始されます。COMMIT 文を発行して変更処理の結果を有効なものと確定するか、ROLLBACK 文を発行してすべての変更処理の結果を無効なものとしてしまうことにより、トランザクションは終了します。
SQL92 及び ORACLE では暗黙的にトランザクションが開始されますが、PostgreSQL では明示的にトランザクションの開始を示しますので、その構文を参考に示します。WORK 句または TRANSACTION 句には特に意味はありません。また省略可能です。
<PostgreSQL>BEGIN [ WORK | TRANSACTION ] ;
トランザクションの終了は、COMMIT 文または ROLLBACK 文で行います。これは SQL92 でも定義されています。すべての処理が正しく実行されたときは COMMIT 文でトランザクションを終了します。処理が正しく実行できなかったときは、ROLLBACK 文でトランザクションを取り消します。
COMMIT 文は次のとおり定義されています。
COMMIT [ WORK ] ;
ROLLBACK 文の構文は次の通りです。
ROLLBACK [ WORK ] ;
COMMIT 文及び ROLLBACK 文のいずれも WORK 句には意味がなく、省略可能です。
トランザクションの終了で ROLLBACK 文を実行すると、トランザクションが行われる前の状態に戻ってしまいます。しかし、すべての処理を取り消すのではなく、例えば処理 A 実行後に処理 B を行ったが、正しく実行されなかった場合に、トランザクションが行われる前に戻るのではなく、処理 A の直後に戻りたい場合があります。そのような場合には、SAVEPOINT 文を用いて、処理 A の後に目印をつけることにより、ROLLBACK 文でその目印を指定してやれば処理 A の直後に戻ることができます。SAVEPOINT 文の構文は次のとおりです。
SAVEPOINT セーブポイント名 ;
ROLLBACK 文でセーブポイントに戻るには次のように記述します。
ROLLBACK TO SAVEPOINT セーブポイント名 ;
通常、トランザクションを実行するときには、エラーチェックのプログラムを動かし、処理が正しく実行されているかどうか調べながら行います。ここではエラーチェックの方法についての説明はしませんが、このエラーチェックの結果により COMMIT 文で終了するのか、ROLLBACK 文で終了するのかを決定します。
具体的な例は用いませんが、トランザクションの実行についての例を sample.23-1 に示します。
-- sample.23-1 --/* トランザクション */ (BEGIN WORK ; ) /* PostgreSQL の場合 */ INSERT 文 ; /* トランザクションの開始 */ COMMIT ; /* 処理の確定 */ (BEGIN WORK ; ) /* PostgreSQL の場合 */ UPDATE 文 ; /* トランザクションの開始 */ ROLLBACK ; /* 処理の取り消し */ (BEGIN WORK ; ) /* PosgreSQL の場合 */ DELETE 文 ; /* トランザクションの開始 */ SAVEPOINT sPOINT ; /* セーブポイントの設定 */ INSERT 文 ; ROLLBACK TO SAVEPOINT sPOINT ; /* セーブポイントへ戻る */ INSERT 文 ; COMMIT ; /* 処理の確定 */