3.4. トランザクション

トランザクション はすべてのデータベースシステムで基礎となる概念です。トランザクションの基本的要点は複数の手順を単一の「すべてか無しか」の操作にまとめあげることです。手順の進行途中の状態はほかの動いているトランザクションからは見えません。 そして、なんらかのエラーが引き起こるとトランザクションの完結を防ぐのです。 ですからデータベースはエラーの原因となった手順によってまったく影響されることはありません。

例えば銀行のデータベースでそこに多数の顧客の口座の残高と支店の総預金残高が含まれていることを考えてみます。アリスの口座からボブの口座に $100.00 の支払があったことを記録したいとします。ちょっと乱暴に単純化するとこの SQL はつぎのようになります。

UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');

これらのコマンドの詳しいことはここでは重要でありません。重要な点はこのかなり単純な操作においていくつかの目的が果たされなくてはならない独立した更新手続きが係わっていることです。銀行の職員としてはこれらすべての更新が生じるかあるいはまったく生じないかいずれかの確証が欲しいところです。アリスの口座から引き落されることなく $100.00 をボブが受け取るようなシステム故障があってはならないことは間違いありません。いっぽうボブに振り込まれることなくアリスの口座から引き落としがあれば、もうアリスは過去将来におけるお得意様ではなくなるでしょう。操作の途中でなにか不都合が発生した場合、効果を及ぼすどのような手順も実行しない確証が必要です。更新手順を トランザクションにグループ分けをするとその確証が得られます。 トランザクションはほかのトランザクションから見て完結するかまったく起こらなかったかという見地から原子的であると呼ばれます。

また同時にいったんトランザクションが完結しデータベースシステムで承認されたばあいは確かに永久に記録され直後にクラッシュが起きても失われないという確証も必要です。例えばボブの口座からの現金引き落としを記録する場合、ボブの口座の借方記帳が現金とともになくなってしまうような偶然があって欲しくはありません。 ちょうど銀行の店舗からボブが単に立ち去るように。トランザクション保護のデータベースはひとつのトランザクションによるすべての更新をそのトランザクションが完結したと通知される前に (ディスクなどの) 固定記録装置にログすることにで保証します。

もうひとつのトランザクション保護データベースの重要な特性は原子的更新という概念に深く関係していることです。複数のトランザクションが同時に動作しているとき、それぞれのトランザクションは別のトランザクションがおこなっている未完了の変更を見ることができてはなりません。例えば、ひとつのトランザクションがすべての支店の残高を集計する作業をしているとき、ボブの口座がある支店への貸方記帳を含めずにアリスの口座がある支店からの借方記帳を含めたり、また、その逆を含めたりした集計をしてはいけません。ですからトランザクションはデータベースに対する永久効果という意味のみならず操作の場合の可視性において「すべてか無しか」でなければなりません。作業中のトランザクションによる更新はほかのトランザクションからはトランザクションが完結するまで不可視です。 完結したその時点ですべての更新が同時に見えるようになります。

PostgreSQL ではトランザクションを構成する SQL コマンドを BEGINCOMMIT で囲んで設定します。そうすると、この銀行取り引きのトランザクションは実際つぎのようになります。

BEGIN;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
-- etc etc
COMMIT;

トランザクション処理の途中でコミットを行わない (アリスの口座残高が足りなかったような場合) と判断した場合は COMMIT ではなく ROLLBACK を使用して、行なわれたすべての更新を破棄します。

PostgreSQL は実際すべての SQL 命令文をトランザクション内で実行するようになっています。BEGIN を発行しないでもそれぞれの命令文は暗黙的な BEGIN がついているとみなし (成功すれば) COMMIT で囲まれたものとします。BEGINCOMMIT で囲まれた命令文のグループは トランザクションブロックと呼ばれることもあります。

Note: いくつかのクライアントライブラリは自動的に BEGINCOMMIT コマンドを発行し、尋ねること無しにトランザクションブロックが有効になるようにします。使用しているインターフェイスのドキュメントをご覧ください。