バージョンごとのドキュメント一覧

3.4. トランザクション #

<title>Transactions</title>

<firstterm>Transactions</firstterm> are a fundamental concept of all database systems. The essential point of a transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all. トランザクションは全てのデータベースシステムで基礎となる概念です。 トランザクションの基本的要点は複数の手順を単一の「全てか無しか」の操作にまとめ上げることです。 手順の進行途中の状態は他の同時実行中のトランザクションからは見えません。 トランザクションの完結の障害となる何らかのエラーが起こると、それらの手順はどれもデータベースにまったく影響を与えません。

For example, consider a bank database that contains balances for various customer accounts, as well as total deposit balances for branches. Suppose that we want to record a payment of $100.00 from Alice's account to Bob's account. Simplifying outrageously, the SQL commands for this might look like: 例を挙げましょう。ある銀行のデータベースでそこに多数の顧客の口座残高と支店の総預金残高が記録されているとします。 アリスの口座からボブの口座に$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');

The details of these commands are not important here; the important point is that there are several separate updates involved to accomplish this rather simple operation. Our bank's officers will want to be assured that either all these updates happen, or none of them happen. It would certainly not do for a system failure to result in Bob receiving $100.00 that was not debited from Alice. Nor would Alice long remain a happy customer if she was debited without Bob being credited. We need a guarantee that if something goes wrong partway through the operation, none of the steps executed so far will take effect. Grouping the updates into a <firstterm>transaction</firstterm> gives us this guarantee. A transaction is said to be <firstterm>atomic</firstterm>: from the point of view of other transactions, it either happens completely or not at all. 書かれているSQLコマンドの詳しいことについて、ここでは重要でありません。 重要な点は、この単純な操作の目的を果たすため、複数の独立した更新手続きが関わっていることです。 銀行職員としてはこれら全ての更新が行われるかもしくはまったく行われないのかいずれかの確証が必要です。 $100.00がアリスの口座から引き落とされずにボブの口座に振り込まれるようなシステムの不備があってはなりません。 一方、$100.00がボブに振り込まれないでアリスの口座から引き落とされたとしたら、アリスはこの銀行のお得意様ではなくなるでしょうね。 操作の途中で一部不都合が発生した場合、結果に影響を与えるいかなる手続きも実行されないという確証が必要です。 更新手続きをトランザクションにグループ化すると、その確証が得られます。 あるトランザクションは他のトランザクションから見て完結するかまったく起こらなかったかという見方から原子的と呼ばれます。

We also want a guarantee that once a transaction is completed and acknowledged by the database system, it has indeed been permanently recorded and won't be lost even if a crash ensues shortly thereafter. For example, if we are recording a cash withdrawal by Bob, we do not want any chance that the debit to his account will disappear in a crash just after he walks out the bank door. A transactional database guarantees that all the updates made by a transaction are logged in permanent storage (i.e., on disk) before the transaction is reported complete. もう一方で、いったんトランザクションが完結しデータベースシステムに承認された場合は、確実に恒久的に保存され、たとえ直後にクラッシュが起こったとしても記録は失われないという確証も必要です。 例えばボブが自分の口座から現金を引き落として店舗を立ち去った直後にボブの口座からの引き落とし記録がシステムのクラッシュで消えてしまうことは受け入れられません。 トランザクションが実装されているデータベースでは、あるトランザクションによる全ての更新がそのトランザクションを完結したと通知を行う前に永続的記録装置(すなわちディスク上)にログを書き込むことで保証しています。

Another important property of transactional databases is closely related to the notion of atomic updates: when multiple transactions are running concurrently, each one should not be able to see the incomplete changes made by others. For example, if one transaction is busy totalling all the branch balances, it would not do for it to include the debit from Alice's branch but not the credit to Bob's branch, nor vice versa. So transactions must be all-or-nothing not only in terms of their permanent effect on the database, but also in terms of their visibility as they happen. The updates made so far by an open transaction are invisible to other transactions until the transaction completes, whereupon all the updates become visible simultaneously. トランザクションを実装したデータベースの別の重要な特性は、原子的更新という概念に深く関係しています。 複数のトランザクションが同時に動作している時、それぞれのトランザクションは別のトランザクションが行っている未完了の変更を見ることができてはなりません。 例えば、あるトランザクションがすべての支店の残高を集計する作業を行っているとき、アリスの口座がある支店からの引き落としを勘定に入れるけれども、ボブの口座がある支店への振り込みを勘定に入れないというのは受け入れられませんし、その逆も駄目です。 つまり、データベース上での恒久的効果という意味のみならず、一連の操作の過程で可視性ということにおいてもトランザクションは「すべて」か「なし」かでなければなりません。 作業中のトランザクションによる更新は、他のトランザクションからはトランザクションが完結するまで不可視です。 そのトランザクションが完結したその時点で、トランザクションで行った更新の全てが見えるようになります。

In <productname>PostgreSQL</productname>, a transaction is set up by surrounding the SQL commands of the transaction with <command>BEGIN</command> and <command>COMMIT</command> commands. So our banking transaction would actually look like: PostgreSQLではトランザクションを構成するSQLコマンドをBEGINCOMMITで囲んで設定します。 従って、この銀行取引のトランザクションの実際は次のようになります。

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

&#45;- etc etc

-- 等々
COMMIT;

If, partway through the transaction, we decide we do not want to commit (perhaps we just noticed that Alice's balance went negative), we can issue the command <command>ROLLBACK</command> instead of <command>COMMIT</command>, and all our updates so far will be canceled. トランザクション処理の途中でコミットを行わない(アリスの口座残高が足りなかったような場合)と判断した場合は、COMMITではなくROLLBACKを使用して行った全ての更新を破棄します。

<productname>PostgreSQL</productname> actually treats every SQL statement as being executed within a transaction. If you do not issue a <command>BEGIN</command> command, then each individual statement has an implicit <command>BEGIN</command> and (if successful) <command>COMMIT</command> wrapped around it. A group of statements surrounded by <command>BEGIN</command> and <command>COMMIT</command> is sometimes called a <firstterm>transaction block</firstterm>. PostgreSQLは実際全てのSQL文をトランザクション内で実行するようになっています。 BEGINを発行しない場合、それぞれの文は暗黙的にBEGINが付いているとみなし、(成功すれば)COMMITで囲まれているものとします。 BEGINCOMMITで囲まれた文のグループはトランザクションブロックと呼ばれることもあります。

注記

Some client libraries issue <command>BEGIN</command> and <command>COMMIT</command> commands automatically, so that you might get the effect of transaction blocks without asking. Check the documentation for the interface you are using. いくつかのクライアントライブラリは自動的にBEGINCOMMITコマンドを発行し、ユーザに尋ねることなくトランザクションブロックが有効になります。 使用しているインタフェースのドキュメントで確認してください。

It's possible to control the statements in a transaction in a more granular fashion through the use of <firstterm>savepoints</firstterm>. Savepoints allow you to selectively discard parts of the transaction, while committing the rest. After defining a savepoint with <command>SAVEPOINT</command>, you can if needed roll back to the savepoint with <command>ROLLBACK TO</command>. All the transaction's database changes between defining the savepoint and rolling back to it are discarded, but changes earlier than the savepoint are kept. セーブポイントを使用することで、トランザクション内で文を、より粒度を細かく制御することが可能になります。 セーブポイントは、トランザクションを構成するある部分を選択的に破棄する一方、破棄されない残りの部分をコミットします。 SAVEPOINTコマンドでセーブポイントを定義した後、必要であればROLLBACK TOコマンドによりセーブポイントまでロールバックできます。 定義されたセーブポイントとロールバックするポイントとの間の全てのトランザクションのデータベースの変更は破棄されますが、セーブポイント以前の変更は保持されます。

After rolling back to a savepoint, it continues to be defined, so you can roll back to it several times. Conversely, if you are sure you won't need to roll back to a particular savepoint again, it can be released, so the system can free some resources. Keep in mind that either releasing or rolling back to a savepoint will automatically release all savepoints that were defined after it. セーブポイントまでロールバックした後でもセーブポイントは定義されたままです。このため何度でもそこにロールバックできます。 逆に再度特定のセーブポイントにロールバックする必要がないのであれば、それを解除しシステムリソースを多少とも解放できます。 あるセーブポイントを解除したりセーブポイントにロールバックすることにより、自動的にその後に定義されたすべてのセーブポイントが解除されることに注意してください。

All this is happening within the transaction block, so none of it is visible to other database sessions. When and if you commit the transaction block, the committed actions become visible as a unit to other sessions, while the rolled-back actions never become visible at all. これら全てはトランザクションブロック内で起こるので、他のデータベースセッションからは何も見えません。 トランザクションブロックをコミットした場合、他のセッションからはコミットされた行為が1つの単位として見えるようになりますが、ロールバックの行為は決して可視になりません。

Remembering the bank database, suppose we debit $100.00 from Alice's account, and credit Bob's account, only to find later that we should have credited Wally's account. We could do it using savepoints like this: 銀行のデータベースを思い出してください。アリスの口座から$100.00を引き出してボブの口座に振り込むとします。後になってボブではなくウィリーの口座に振り込むべきだったと気が付きました。 この場合セーブポイントを次のように使います。

BEGIN;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';

&#45;- oops ... forget that and use Wally's account

-- おっと、忘れるところだった。ウィリーの口座を使わなければ。
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Wally';
COMMIT;

This example is, of course, oversimplified, but there's a lot of control possible in a transaction block through the use of savepoints. Moreover, <command>ROLLBACK TO</command> is the only way to regain control of a transaction block that was put in aborted state by the system due to an error, short of rolling it back completely and starting again. この例はもちろん極端に単純化していますが、セーブポイントの使用を通じてトランザクションブロック内で多くの制御を行えることがわかります。 さらには何らかのエラーでシステムがトランザクションブロックを中断状態にした場合、完全にロールバックして再び開始するのを別とすれば、ROLLBACK TOコマンドがトランザクションブロックの制御を取り戻す唯一の手段です。