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');

書かれている SQL コマンドの詳しいことについて今のところ重要でありません。重要な点はどちらかといえばこの単純な操作の目的を果たすための独立した更新手続きが係わっていることです。銀行職員としてはこれらすべての更新が行われるかもしくはまったく行われないのかいずれかの確証が必要です。$100.00 がアリスの口座から引き落されずにボブの口座に振り込まれるようなシステムの不備があってはなりません。一方、$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 で囲まれた命令文のグループは トランザクションブロックと呼ばれることもあります。

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