10 トランザクション
この章では、トランザクションを定義し、データベースでトランザクションが処理される方法について説明します。
この章の構成は、次のとおりです。
トランザクションの概要
トランザクションは、1つ以上のSQL文を含むアトミックな論理作業単位です。
トランザクションは、SQL文をグループ化して、すべての文がコミットされた(データベースに適用された)状態にするか、すべての文がロールバックされた(データベースから取り消された)状態にできる必要があります。Oracle Databaseでは、すべてのトランザクションにトランザクションIDと呼ばれる一意の識別子が割り当てられます。
すべてのOracleトランザクションは、ACIDプロパティと呼ばれる、データベース・トランザクションの基本プロパティに従います。ACIDは次の単語の頭字語です。
-
Atomicity(原子性)
1つのトランザクションでは、すべてのタスクが実行されるか、1つも実行されないかのいずれかです。部分的に実行されるトランザクションは存在しません。たとえば、トランザクションで100行の更新が開始され、20行が更新された後にシステムで障害が発生した場合、データベースではこの20行に行われた変更がロールバックされます。
-
Consistency(一貫性)
トランザクションにより、データベースは一貫したある状態から一貫した別の状態に移行します。たとえば、普通預金口座の借方に記入し、当座預金口座の貸方に記入する銀行のトランザクションにおいて、障害によって、データベースで一方の口座でのみ貸方に記入されたためにデータの一貫性がなくなることは許されません。
-
Isolation(独立性)
トランザクションの結果は、そのトランザクションがコミットされるまで、他のトランザクションに表示されません。たとえば、
hr.employees
表を更新しているユーザーには、別のユーザーがemployees
に対して同時に行った未コミットの変更は表示されません。このため、ユーザーには、トランザクションがシリアルに実行されているように見えます。 -
Durability(永続性)
コミットされたトランザクションによって行われた変更は、永続的に確定されます。トランザクションの完了後、データベースではリカバリ・メカニズムを使用して、トランザクションによる変更が失われていないことが確認されます。
トランザクションの使用は、データベース管理システムとファイルシステムの最も重要な違いの1つです。
サンプル・トランザクション: 口座の借方と貸方
トランザクションの概念を具体的に説明するため、銀行業務データベースについて考えてみます。
顧客が普通預金口座から当座預金口座へ預金を振り替える場合、トランザクションは次の3つの別々の操作で構成する必要があります。
-
普通預金口座の減額
-
当座預金口座の増額
-
トランザクション・ジャーナルへのトランザクションの記録
Oracle Databaseでは、2つの状況が考慮されます。3つのSQL文のすべてにおいて口座の差引残高の帳尻が合えば、トランザクションの結果をデータベースに適用できます。ただし、預金額の不足、口座番号が無効、またはハードウェア障害などの問題が原因で、トランザクション内の1つまたは2つの文が完了しない場合は、データベースではすべての口座の差引残高が正しく維持されるようにトランザクション全体をロールバックする必要があります。
次の図に、銀行のトランザクションを示します。最初の文では、普通預金口座3209から$500を減額します。2番目の文では、当座預金口座3208に$500を増額します。3番目の文では、ジャーナルの表にこの振替のレコードを挿入します。最後の文で、トランザクションをコミットします。
トランザクションの構造
データベース・トランザクションは、1つ以上の文で構成されています。
具体的には、トランザクションは次のいずれかで構成されています。
-
全体でデータベースに対するアトミックな変更を構成する1つ以上のデータ操作言語(DML)文
-
1つのデータ定義言語(DDL)文
トランザクションには、開始と終了があります。
関連項目:
-
SQL文のタイプについては、Oracle Database SQL言語リファレンスを参照してください。
トランザクションの開始
トランザクションは、最初の実行可能SQL文が検出された時点で開始されます。
実行可能SQL文は、DML文やDDL文、およびSET TRANSACTION
文など、データベース・インスタンスへのコールを生成するSQL文のことです。
トランザクションが開始されると、Oracle Databaseはそのトランザクションを使用可能なUNDOデータ・セグメントに割り当てて、新しいトランザクションのUNDOエントリを記録します。トランザクションIDは、UNDOセグメントおよびトランザクション表スロットが割り当てられるまでは割り当てられません(割当ては、最初のDML文の実行中に行われます)。トランザクションIDはトランザクションに対して一意であり、UNDOセグメント番号、スロットおよび順序番号を表します。
次の例では、UPDATE
文を実行してトランザクションを開始し、このトランザクションの詳細をV$TRANSACTION
に問い合せます。
SQL> UPDATE hr.employees SET salary=salary;
107 rows updated.
SQL> SELECT XID AS "txn id", XIDUSN AS "undo seg", XIDSLOT AS "slot",
2 XIDSQN AS "seq", STATUS AS "txn status"
3 FROM V$TRANSACTION;
txn id undo seg slot seq txn status
---------------- ---------- ---------- ---------- ----------------
0600060037000000 6 6 55 ACTIVE
関連項目:
トランザクションの終了
トランザクションは、様々な状況で終了する可能性があります。
トランザクションは、次のいずれかのアクションが発生すると終了します。
-
COMMIT
文またはROLLBACK
文が、SAVEPOINT
句なしで発行される場合。コミットでは、ユーザーが明示的または暗黙的に、このトランザクションの変更内容を確定するように要求します。トランザクションによって行われた変更内容が確定され、トランザクションのコミット後にのみ他のユーザーが参照できるようになります。
-
CREATE
、DROP
、RENAME
またはALTER
などのDDLコマンドが実行される場合。データベースでは、すべてのDDL文の前後に暗黙的な
COMMIT
文が発行されます。現行のトランザクションにDML文が含まれている場合、Oracle Databaseは最初にそのトランザクションをコミットし、新しい単一文トランザクションとしてそのDDL文を実行し、コミットします。 -
ユーザーがほとんどのOracle Databaseユーティリティおよびツールを正常に終了する場合(このような場合は、現行のトランザクションが暗黙的にコミットされます)。ユーザーが切断したときのコミット動作は、アプリケーションに依存しており、構成可能です。
ノート:
アプリケーションでは、プログラムを終了する前に、必ず明示的にトランザクションをコミットまたは取り消す必要があります。
-
クライアント・プロセスが異常終了し、トランザクション表およびUNDOセグメントに格納されていたメタデータを使用して、トランザクションが暗黙的にロールバックされる場合。
1つのトランザクションが終了すると、次の実行可能SQL文によって次のトランザクションが自動的に開始されます。次の例では、UPDATE
を実行してトランザクションを開始し、ROLLBACK
文でトランザクションを終了してから、UPDATE
を実行して新しいトランザクションを開始します(トランザクションIDが異なることに注意してください)。
SQL> UPDATE hr.employees SET salary=salary;
107 rows updated.
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
XID STATUS
---------------- ----------------
0800090033000000 ACTIVE
SQL> ROLLBACK;
Rollback complete.
SQL> SELECT XID FROM V$TRANSACTION;
no rows selected
SQL> UPDATE hr.employees SET last_name=last_name;
107 rows updated.
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
XID STATUS
---------------- ----------------
0900050033000000 ACTIVE
関連項目:
-
コミットで終了するトランザクションの例については、「サンプル・トランザクション: 口座の借方と貸方」を参照してください。
-
COMMIT
について学習するには、Oracle Database SQL言語リファレンスを参照してください
文レベルの原子性
Oracle Databaseでは、文レベルの原子性(SQL文がアトミックな作業単位であり、完全に成功するか、完全に失敗するかのいずれかであること)がサポートされます。
正常に実行される文とコミットされるトランザクションとは異なります。1つのSQL文は、アトミックな単位として解析され、エラーなしで実行された場合、たとえば複数行の更新ですべての行が変更されたときなどに、正常に実行されます。
実行中にSQL文が原因でエラーが発生すると成功しないため、この文のすべての結果がロールバックされます。この操作が文レベルのロールバックです。この操作には次のような特徴があります。
-
SQL文が成功しなかった場合は、SQLでの実行予定の作業のみが影響を受けます。
成功しなかった文が、現行のトランザクションにおけるこれまでの作業に影響を及ぼすことはありません。たとえば、「サンプル・トランザクション: 口座の借方と貸方」で、2番目の
UPDATE
文でエラーが発生してロールバックされた場合、最初のUPDATE
文によって実行された作業はロールバックされません。最初のUPDATE
文は、ユーザーが明示的にコミットまたはロールバックできます。 -
ロールバックの効果は、その文がまったく実行されなかった場合と同じ状態にすることです。
アトミックな文の副次的な効果としては、たとえば、文の実行時に起動されたトリガーが、アトミックな文の一部とみなされることがあげられます。アトミックな文の一部として生成された作業は、すべてが成功するか、1つも成功しないかのいずれかです。
文レベル・ロールバックの原因となるエラーの例として、重複する主キーの挿入を試行する場合があります。1つのデッドロック(同じデータに関する競合)に単一SQL文が複数関係している場合も、文レベル・ロールバックが発生します。ただし、SQL文の解析中に構文エラーなどのエラーが検出された場合は、まだSQL文は実行されていないため、文レベルのロールバックは発生しません。
関連項目:
システム変更番号(SCN)
システム変更番号(SCN)は、Oracle Databaseで使用される論理的な内部タイムスタンプです。
SCNを使用して、トランザクションのACIDプロパティに準拠する必要があるデータベース内で発生するイベントに順序を付けます。Oracle DatabaseではSCNを使用して、すべての変更がディスク上に存在することが認識される前のSCNをマークし、リカバリで不要なREDOが適用されないようにします。さらに、データの集合に対するREDOが存在しない時点のマークにもSCNを使用し、リカバリを停止できるようにします。
SCNは直線的に増加する順序で発生します。監視されたSCNは時間における論理的なある時点を示し、監視を繰り返すと等しい値または前よりも大きな値が戻されるため、Oracle DatabaseではSCNを実時間のように使用できます。あるイベントのSCNが別のイベントのSCNよりも小さい場合、このイベントはそのデータベースで先に発生したことになります。複数のイベントが同じSCNを共有する場合もあり、これはイベントがデータベースで同じ時間に発生したことを意味します。
すべてのトランザクションには、SCNがあります。たとえば、トランザクションで行が更新されると、データベースではこの更新が発生したときのSCNが記録されます。このトランザクションで行われたその他の変更にも同じSCNが付けられます。トランザクションがコミットされると、データベースではこのコミットのSCNが記録されます。
Oracle Databaseでは、SCNがシステム・グローバル領域(SGA)で増分されます。トランザクションでデータが変更されると、データベースではこのトランザクションに割り当てられたUNDOデータ・セグメントに新しいSCNが書き込まれます。次に、ログ・ライター・プロセスによって、このトランザクションのコミット・レコードがオンラインREDOログに即時に書き込まれます。コミット・レコードには、トランザクションの一意のSCNが付けられています。Oracle Databaseでは、SCNをインスタンス・リカバリ・メカニズムおよびメディア・リカバリ・メカニズムの一部としても使用します。
トランザクション制御の概要
トランザクション制御は、DML文による変更の内容を管理し、一覧のDML文をトランザクションとしてグループ化する処理です。
通常、アプリケーション設計者は、作業が論理単位で完了してデータの一貫性が保たれるよう、トランザクション制御を考慮します。
トランザクション制御では、「トランザクション制御文」で説明したように、次の文が使用されます。
-
COMMIT
文は、現行のトランザクションを終了し、トランザクションで実行されたすべての変更を確定します。さらに、COMMIT
文により、トランザクション内のすべてのセーブポイントが消去され、トランザクション・ロックが解放されます。 -
ROLLBACK
文は、現行のトランザクションで行われた作業を元に戻し、最後のCOMMIT
またはROLLBACK
以降に行われたすべてのデータ変更が破棄されます。ROLLBACK TO SAVEPOINT
文は、最後のセーブポイント以降の変更を取り消しますが、トランザクション全体は終了しません。 -
SAVEPOINT
文は、後からロールバックできるトランザクションの時点を特定します。
表10-1のセッションは、トランザクション制御の基本概念を示しています。
表10-1 トランザクション制御
T | セッション | 説明 |
---|---|---|
t0 |
|
セッション内の既存のトランザクションを終了します。 |
t1 |
|
トランザクションを開始し、トランザクションに |
t2 |
|
Bandaの給与を7000に更新します。 |
t3 |
|
|
t4 |
|
Greeneの給与を12000に更新します。 |
t5 |
|
|
t6 |
|
トランザクションをt3までロールバックし、t4で行われたGreeneの給与の更新を取り消します。 |
t7 |
|
トランザクション |
t8 |
|
トランザクション |
t9 |
|
セッションで新しいトランザクションを開始し、トランザクションに |
t10 |
|
Bandaの給与を7050に更新します。 |
t11 |
|
Greeneの給与を10950に更新します。 |
t12 |
|
トランザクション |
関連項目:
トランザクション制御文について学習するには、『Oracle Database SQL言語リファレンス』を参照してください。
トランザクション名
トランザクション名は、ユーザー指定のオプションのタグであり、トランザクションが実行する作業のリマインダとして機能します。トランザクションの命名にはSET TRANSACTION
...
NAME
文を使用し、トランザクションの最初の文として使用する必要があります。
表10-1では、最初のトランザクションがsal_update
、2つ目のトランザクションがsal_update2
と命名されています。
トランザクション名を使用すると、次のような利点があります。
-
名前を付けることで、長時間実行中のトランザクションの監視およびインダウト分散トランザクションの解決が容易になります。
-
アプリケーションのトランザクションIDとともにトランザクション名を表示できます。たとえば、システムの活動状況を監視する場合、データベース管理者はOracle Enterprise Manager(Enterprise Manager)内のトランザクション名を表示できます。
-
トランザクション名はトランザクション監査REDOレコードに書き込まれるため、LogMinerを使用してREDOログ内の特定のトランザクションを検索できます。
-
トランザクション名を使用して、
V$TRANSACTION
などのデータ・ディクショナリ・ビュー内の特定のトランザクションを検索できます。
関連項目:
-
V$TRANSACTION
について学習するには、『Oracle Databaseリファレンス』を参照してください -
SET TRANSACTION
について学習するには、『Oracle Database SQL言語リファレンス』を参照してください
アクティブなトランザクション
アクティブなトランザクションとは、開始した後、まだコミットまたはロールバックされていないトランザクションのことです。
表10-1では、sal_update
トランザクションでデータを変更する最初の文が、Bandaの給与の更新です。この更新の実行が成功してからROLLBACK
文がトランザクションを終了するまで、sal_update
トランザクションはアクティブです。
トランザクションによるデータ変更は、トランザクションがコミットまたはロールバックされるまでは一時的です。トランザクションが終了する前のデータの状態は、次の表のとおりです。
表10-2 トランザクションが終了する前のデータの状態
状態 | 説明 | さらに学習するには |
---|---|---|
Oracle Databaseにより、SGAにUNDO情報が生成されています。 |
このUNDOデータには、トランザクションのSQL文によって変更された古いデータ値が含まれています。 |
|
Oracle Databaseにより、SGAのオンラインREDOログ・バッファにREDOが生成されています。 |
REDOログ・レコードには、データ・ブロックおよびUNDOブロックに対する変更内容が含まれています。 |
|
SGAのデータベース・バッファに変更が加えられます。 |
コミットされたトランザクションのデータ変更は、SGAのデータベース・バッファに格納されており、データベース・ライター(DBW)によりデータファイルに必ずしもすぐに書き込まれるわけではありません。ディスクへの書込みは、コミットの前に行われることも、後に行われることもあります。 |
|
データ変更の影響を受ける行はロックされます。 |
他のユーザーは、影響を受ける行のデータを変更することも、未コミットの変更を表示することもできません。 |
セーブポイント
セーブポイントは、トランザクションのコンテキスト内のユーザー宣言による中間マーカーです。
内部的には、セーブポイント・マーカーはSCNに解決されます。セーブポイントは、ロング・トランザクションをいくつかの小さい部分に分割します。
ロング・トランザクションでセーブポイントを使用すると、そのトランザクション内の宣言されたセーブポイントからトランザクション内の現時点までの間に実行された作業を、後でロールバックできるようになります。したがって、エラーが発生してもすべての文を再発行する必要はありません。表10-1では、セーブポイントafter_banda_sal
を作成しているため、Greeneの給与に対する更新をこのセーブポイントまでロールバックできます。
セーブポイントへのロールバック
未コミットのトランザクションにおけるセーブポイントへのロールバックは、指定したセーブポイント後に行われたすべての変更の取消しを意味しますが、トランザクション自体のロールバックは意味しません。
表10-1でROLLBACK TO SAVEPOINT after_banda_sal
を実行したときのように、トランザクションがセーブポイントまでロールバックされると、次の処理が行われます。
-
Oracle Databaseにより、セーブポイントの後に実行された文のみがロールバックされます。
表10-1では、
ROLLBACK TO SAVEPOINT
により、Greeneに対するUPDATE
がロールバックされますが、Bandaに対するUPDATE
はロールバックされません。 -
Oracle Databaseでは、
ROLLBACK TO SAVEPOINT
文に指定されたセーブポイントは保存されますが、それより後のセーブポイントはすべて失われます。表10-1では、
ROLLBACK TO SAVEPOINT
によってafter_greene_sal
セーブポイントが失われます。 -
Oracle Databaseにより、指定したセーブポイントの後に取得された表と行のすべてのロックが解放されますが、そのセーブポイントより前に取得されたすべてのデータ・ロックは保持されます。
トランザクションはアクティブであり、継続できます。
関連項目:
-
ROLLBACK
文およびSAVEPOINT
文について学習するには、『Oracle Database SQL言語リファレンス』を参照してください。 -
トランザクション処理および制御について学習するには、『Oracle Database PL/SQL言語リファレンス』を参照してください。
トランザクションのエンキュー
状況によっては、以前にロックされたリソースを待機中のトランザクションが、セーブポイントへのロールバック後も引き続きブロックされる場合があります。
トランザクションが別のトランザクションによってブロックされた場合、このトランザクションはブロックしているトランザクション上でエンキューされるため、ブロックされたトランザクションを続行するには、ブロックしているトランザクション全体をコミットまたはロールバックする必要があります。
次の表に示すシナリオでは、セッション1でDML文が実行される前に作成されたセーブポイントに、セッション1がロールバックされます。ただし、セッション2はセッション1のトランザクションの完了を待機するため、引き続きブロックされます。
表10-3 セーブポイントへのロールバックの例
T | セッション1 | セッション2 | セッション3 | 説明 |
---|---|---|---|---|
t0 |
UPDATE employees SET salary=7000 WHERE last_name= 'Banda'; |
セッション1でトランザクションが開始されます。このセッションでは、 |
||
t1 |
SAVEPOINT after_banda_sal; |
セッション1により、 |
||
t2 |
UPDATE employees SET salary=12000 WHERE last_name= 'Greene'; |
セッション1により、 |
||
t3 |
UPDATE employees SET salary=14000 WHERE last_name= 'Greene'; |
セッション2により、 |
||
t4 |
ROLLBACK TO SAVEPOINT after_banda_sal; |
セッション1により、 この時点で、セッション2は引き続きセッション1にブロックされています。これは、まだ完了していないセッション1のトランザクション上でセッション2がエンキューされているためです。 |
||
t5 |
UPDATE employees SET salary=11000 WHERE last_name= 'Greene'; |
|
||
t6 |
COMMIT; |
セッション1がコミットし、そのトランザクションが終了します。セッション2は現在、セッション3のトランザクションの後で |
関連項目:
Oracle Databaseによってロックが解放される時期についてさらに学習するには、「ロックの期間」を参照してください
トランザクションのロールバック
未コミットのトランザクションをロールバックすると、そのトランザクション内のSQL文によって実行された、データに対するすべての変更が取り消されます。
トランザクションのロールバック後には、そのトランザクション内で実行された作業の結果は存在しません。セーブポイントを参照しないで、トランザクション全体をロールバックした場合、Oracle Databaseでは次の処理が実行されます。
-
トランザクションのすべてのSQL文によるすべての変更が、対応するUNDOセグメントを使用して取り消されます。
すべてのアクティブなトランザクションのトランザクション表エントリには、そのトランザクションのすべてのUNDOデータを示すポインタが(適用時とは逆の順序で)格納されています。データベースでは、UNDOセグメントからデータを読み取り、操作を逆順にして、適用されたとおりにUNDOエントリをマークします。したがって、トランザクションで行が挿入されると、ロールバックによって削除されます。トランザクションで行が更新されると、ロールバックによって更新が元に戻されます。トランザクションで行が削除されると、ロールバックによって再挿入されます。表10-1では、GreeneとBandaの給与の更新が、
ROLLBACK
によって元に戻されています。 -
トランザクションで保持されているすべてのデータ・ロックが解放されます。
-
トランザクション内のすべてのセーブポイントが消去されます。
表10-1では、
ROLLBACK
によってセーブポイントafter_banda_sal
が削除されています。セーブポイントafter_greene_sal
は、ROLLBACK TO SAVEPOINT
文によって削除されています。 -
トランザクションを終了します
表10-1では、
ROLLBACK
によって、データベースは最初のCOMMIT
が実行された後と同じ状態で残ります。
ロールバックの持続時間は、変更されたデータ量の関数になります。
関連項目:
-
ROLLBACK
コマンドについて学習するには、Oracle Database SQL言語リファレンスを参照してください。
トランザクションのコミット
コミットは、現行のトランザクションを終了し、トランザクションで実行されたすべての変更を確定します。
表10-1では、2つ目のトランザクションがsal_update2
で開始され、明示的なCOMMIT
文で終了しています。これにより、2つのUPDATE
文の結果である変更が確定されます。
トランザクションをコミットすると、次のアクションが実行されます。
-
データベースにより、
COMMIT
のSCNが生成されます。関連するUNDO表領域の内部トランザクション表に、トランザクションのコミットが記録されます。トランザクションに対応する一意のSCNは、トランザクション表に割り当てられて記録されます。
-
ログ・ライター・プロセス(LGWR)により、REDOログ・バッファ内に残されたREDOログ・エントリがオンラインREDOログに書き込まれ、さらにトランザクションのSCNがオンラインREDOログに書き込まれます。これが、トランザクションのコミットを構成するアトミック・イベントです。
-
Oracle Databaseにより、行と表に対して保持されているロックが解放されます。
未コミットのトランザクションによって保持されているロックを待機してエンキューされていたユーザーが、作業を続行できるようになります。
-
Oracle Databaseにより、セーブポイントが削除されます。
表10-1では、
sal_update
トランザクション内にセーブポイントが存在しないため、消去されたセーブポイントはありません。 -
Oracle Databaseにより、コミットのクリーンアウトが実行されます。
コミットされたトランザクションのデータが含まれている変更済ブロックが引き続きSGA内に存在し、このブロックを変更する他のセッションがない場合は、データベースにより、このブロックからロックに関するトランザクション情報(ITLエントリ)が削除されます。
COMMIT
でブロックを消去し、後続のSELECT
によるこのタスクの実行を不要にすると理想的です。指定された行に対してITLエントリが存在しない場合はロックされません。指定された行に対してITLエントリが存在する場合はロックされている可能性があるため、セッションはこの対象トランザクションがコミットされたかどうかを判断するために、UNDOセグメント・ヘッダーをチェックする必要があります。対象のトランザクションがコミットされている場合、セッションはブロックをクリーンアウトし、これによってREDOが生成されます。ただし、COMMIT
が以前にITLをクリーンアウトした場合、チェックとクリーンアウトは不要です。ノート:
ブロックのクリーンアウトではREDOが生成されるため、問合せによってREDOが生成され、結果として次のチェックポイント時にブロックが書き込まれる場合があります。
-
Oracle Databaseにより、トランザクションに完了のマークが付けられます。
トランザクションをコミットした後、ユーザーは変更を表示できます。
通常のコミットは、トランザクションのサイズにかかわらず高速な操作です。コミットの速度は、トランザクション内で変更されるデータのサイズによって遅くなりません。コミットで最も時間がかかる部分は、LGWRによって実行される物理ディスクI/Oです。ただし、LGWRではREDOログ・バッファの内容が段階的にバックグラウンドで書き込まれるため、LGWRにかかる時間は削減されます。
デフォルトの動作では、LGWRによりREDOがオンラインREDOログに同時に書き込まれ、トランザクションはバッファ内のREDOがディスクに移動するまで待機してから、コミットをユーザーに戻します。ただし、アプリケーション開発者は、トランザクションのコミット待機時間を短縮するために、REDOが非同期に書き込まれ、REDOがディスクに移動されるまでトランザクションが待機せずに、COMMIT
コールからすぐに戻れるよう指定できます。
関連項目:
-
LGWRの詳細は、「バックグラウンド・プロセスの概要」を参照してください
-
非同期コミットの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照
トランザクション・ガードの概要
トランザクション・ガードは、アプリケーションがトランザクションの冪等性を提供するために使用できるAPIの1つであり、これにより、データベースは、トランザクションがコミットされて完了しているかどうかを示す保証付きのコミット結果を保持できます。Oracle Databaseには、JDBCシン、OCI、OCCIおよびODP.Net用のAPIが備わっています。
リカバリ可能エラーは、実行中のアプリケーション・セッション論理と関係なく、外部システムの障害が原因で発生します。リカバリ可能なエラーは、フォアグラウンド・プロセス、ネットワーク、ノード、記憶域およびデータベースの計画および計画外停止の後に発生します。停止によりクライアント・アプリケーションとデータベース間の接続が中断した場合、アプリケーションでは切断エラー・メッセージを受信します。接続切断時に実行中だったトランザクションは、処理中のトランザクションと呼ばれます。
トランザクションを再送信するか、それとも結果(コミット済または未コミット)をクライアントに戻すかどうかを決めるため、アプリケーションでは処理中のトランザクションの結果を判断する必要があります。Oracle Database 12cまでは、クライアントに戻されたコミット・メッセージは残りませんでした。トランザクションをチェックしても、チェック後にそれがコミットされないと保証するものではなく、トランザクションの重複や他の形の論理的な破損が生じる可能性があります。たとえば、ユーザーが本をオンラインで購入する際、Webブラウザをリフレッシュして、同じ本に対して2回請求される可能性があります。
関連項目:
-
トランザクション・ガードについて学習するには、Oracle Database開発ガイドを参照してください
-
トランザクション・ガードのサービスを構成する方法を学習するには、Oracle Real Application Clusters管理およびデプロイメント・ガイドを参照してください
トランザクション・ガードの利点
Oracle Database 12cから、トランザクション・ガードでは、リカバリ可能な停止の後に、処理中のトランザクションのステータスを判断するためのツールがアプリケーションに提供されるようになりました。
トランザクション・ガードを使用すれば、アプリケーションでは、トランザクションが1回しか実行されていないことを確認できます。たとえば、ネット書店アプリケーションで前に送信したコミットが失敗したことが確認されれば、アプリケーションは安全に再送信できます。
トランザクション・ガードでは、アプリケーションで重複送信が実行されないように、実行を1回のみにするためのツールを提供します。トランザクション・ガードでは、トランザクションごとに既知の結果を提供します。
トランザクション・ガードは、Oracle Databaseの中核機能です。アプリケーション・コンティニュイティでは、エンド・ユーザーに停止を隠すときにトランザクション・ガードを使用します。トランザクション・ガードがないと、エラー後に再試行するアプリケーションで、重複トランザクションがコミットされる可能性があります。
関連項目:
-
トランザクション・ガードを使用して、開発者がアプリケーションの高可用性を実現するのを助けるアプリケーション・コンティニュイティについて学習するには、「アプリケーション・コンティニュイティの概要」を参照してください
-
サポートおよび含まれているトランザクションのタイプなど、トランザクション・ガードについて学習するには、Oracle Database開発ガイドを参照してください。
トランザクション・ガードにより行われる処理
この項では、失われたコミット・メッセージの問題と、トランザクション・ガードにより、論理トランザクションIDを使用してその問題がどのように解決されるかについて説明します。
失われたコミット・メッセージ
冪等性の設計時に、開発者は、コミット文送信後の通信エラーの問題に対処する必要があります。コミット・メッセージは、データベースに残らないため、エラー後に取得できません。
次の図は、クライアント・アプリケーションとデータベース間の対話をハイレベルに表現したものです。
標準コミットの場合、データベースではトランザクションをコミットすると、クライアントに成功メッセージを戻します。図10-2では、クライアントがコミット文を送信し、通信が失敗したというメッセージを受信します。このタイプの失敗は、データベース・インスタンスの障害またはネットワークの停止など、いくつかの原因で発生する可能性があります。このシナリオでは、クライアントにはトランザクションの状態がわかりません。
通信の失敗後も、データベースではその送信を続行し、クライアントが切断されていることを認識していない場合があります。トランザクション状態をチェックしても、チェック後にアクティブ・トランザクションがコミットされないという保証にはなりません。この古い情報のために、クライアントがコミットを再送信した場合、データベースではトランザクションを繰り返し、その結果論理的な破損が生じる可能性があります。
論理トランザクションID
Oracle Databaseでは、論理トランザクションIDというグローバルに一意の識別子を使用することで、通信障害を解決します。
このIDには、セッションの最初の接続時に割り当てられた論理セッション番号と、セッションのコミットまたはロールバックごとに更新される実行コミット番号が含まれます。脚注1 アプリケーション側からすると、論理トランザクションIDは、失敗したセッションで送信された最後のデータベース・トランザクションを一意に識別します。
データベースでは、1つ以上のトランザクションがコミットされるクライアントからのラウンド・トリップごとに1つの論理トランザクションIDが格納されます。このIDにより、データをコミットするラウンド・トリップごとに、アプリケーションとデータベース間の対話のために、トランザクション冪等性を提供できます。
1回かぎりのプロトコルにより、データベースに次のことを要求することで、コミット結果へのアクセスが可能になります。
-
再試行のために認められた保持期間中の論理トランザクションIDの維持
-
コミット時の論理トランザクションIDの持続
トランザクションの実行中、データベースとクライアントの両方で、論理トランザクションIDが保持されます。データベースでは、認証時には接続プールから、各ラウンド・トリップでは1つ以上のコミット操作を実行するクライアント・ドライバから借りて、論理トランザクションIDをクライアントに与えます。
リカバリ可能なエラーの後、最後のトランザクションの結果が確認できるように、アプリケーションでは、Java、OCI、OCCIまたはODP.Net APIを使用して、クライアントで保持されている論理トランザクションIDを取得します。次に、アプリケーションではPL/SQLプロシージャDBMS_APP_CONT.GET_LTXID_OUTCOME
を論理トランザクションIDで起動して、最後の送信結果のコミット済(true
またはfalse
)およびユーザー・コール完了(true
またはfalse
)を確認します。
トランザクション・ガードを使用すると、アプリケーションでは、エラーがリカバリ可能で、セッションでの最後のトランザクションがコミットされていない場合、トランザクションを再生できます。最後のトランザクションがコミットされていて、ユーザー・コールが完了している場合、アプリケーションは続行可能です。アプリケーションでは、クライアントが次にとるべきアクションを決定できるように、トランザクション・ガードを使用して既知の結果をクライアントに戻すことができます。
関連項目:
-
論理トランザクションIDについて学習するには、Oracle Database開発ガイドを参照してください
-
DBMS_APP_CONT.GET_LTXID_OUTCOME
プロシージャについてさらに学習するには、Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンスを参照してください
トランザクション・ガード: 例
このシナリオでは、リカバリ可能エラーのためにコミット・メッセージが失われています。
トランザクション・ガードでは、論理トランザクションIDを使用して、COMMIT
文の結果を保存し、トランザクションに既知の結果があることを保証します。
図10-3では、データベースがアプリケーションに、トランザクションがコミットされたかどうか、および最後のユーザー・コールが完了したかどうかを知らせます。その結果、アプリケーションではエンド・ユーザーに結果を戻すことができます。可能性は次のとおりです。
-
トランザクションがコミットされ、ユーザー・コールが完了している場合、アプリケーションではエンド・ユーザーに結果を戻し、続行できます。
-
トランザクションはコミットされているが、ユーザー・コールが完了していない場合、アプリケーションではエンド・ユーザーに警告付きで結果を戻すことができます。例としては、OUTバインドの喪失または処理済行数の喪失などがあります。一部のアプリケーションでは、その他の情報に依存しますが、その他のアプリケーションではそれはありません。
-
ユーザー・コールが完了していない場合、アプリケーションではエンド・ユーザーにこの情報を戻すか、安全に再送信することができます。プロトコルは保証されています。コミット・ステータスからfalseが戻された場合、最後の送信はコミットを阻止されます。
関連項目:
トランザクション・ガードの使用方法を学習するには、Oracle Database開発ガイドを参照してください
アプリケーション・コンティニュイティの概要
アプリケーション・コンティニュイティは、計画および計画外の停止後に完了していないアプリケーション・リクエストをリプレイすることで、アプリケーションから停止を隠そうとします。このような状況では、リクエストがアプリケーションからの作業単位です。
通常、リクエストは、1つのデータベース接続におけるDML文や、1つのWebリクエストに対するその他のデータベース・コールに対応しています。一般に、リクエストは、データベース接続のチェックアウトとチェックインの間で、接続プールから行われるコールにより区別されます。
この項では、次の項目について説明します。
アプリケーション・コンティニュイティの利点
開発者にとっての基本的な問題は、失われたデータベース・セッションをエンド・ユーザーから隠す方法です。
アプリケーション・コンティニュイティでは、コンポーネントによりデータベースとクライアント間の対話が中断した場合、データベース・セッションをリストアすることで、失われたセッションの問題を解決しようとします。リストアされたデータベース・セッションには、すべての状態、カーソル、変数、およびトランザクションが存在する場合は最新のトランザクションが含まれます。
アプリケーション・コンティニュイティのユースケース
典型的な例では、クライアントがデータベースにリクエストを送信すると、トランザクション状態と非トランザクション状態の両方が構築されます。
クライアントでの状態は現行のままですが、入力されたデータ、戻されたデータ、キャッシュされたデータや変数がある可能性があります。ただし、アプリケーションが動作するために必要とするデータベース・セッションの状態は失われます。
クライアント・リクエストにより1つ以上のトランザクションが開始される場合、アプリケーションでは次の可能性に直面します。
-
コミットが発行されている場合、クライアントに戻されるコミット・メッセージは永続的ではありません。クライアントでは、そのリクエストがコミットされたかどうか、非トランザクション処理状態のどこに到達したのかがわかりません。
-
コミットが発行されていないか、発行されたけれども実行されなかった場合、処理中のトランザクションはロールバックされ、正しい状態のセッションを使用して再送信する必要があります。
リプレイが成功した場合、計画および計画外停止のためのデータベース・ユーザー・サービスは中断されません。アプリケーションで表示され、場合によっては実行されているデータ変更をデータベースが検出した場合、リプレイは拒否されます。リプレイ開始の許容時間を超過している場合、アプリケーションで制限されたコールを使用する場合、またはアプリケーションでdisableReplay
メソッドを使用してリプレイを明示的に無効にしている場合、リプレイは試行されません。
関連項目:
データベース・セッションに対するアプリケーション・コンティニュイティの動作についてさらに学習するには、Oracle Real Application Clusters管理およびデプロイメント・ガイドを参照してください
計画的メンテナンスに対するアプリケーション・コンティニュイティ
計画済停止に対するアプリケーション・コンティニュイティにより、アプリケーションは確実に排出または移行できるデータベース・セッションの操作を続行できます。
計画的メンテナンスでは、アプリケーション作業を中断する必要はありません。アプリケーション・コンティニュイティにより、現在の位置からメンテナンスの影響を現在受けていない新しい位置まで排出するためのアクティブな作業時間が提供されます。排出間隔の終了時に、メンテナンスが計画されたデータベース・インスタンス上にセッションが残る可能性があります。アプリケーション・コンティニュイティでは、これらのセッションを強制的に切断するかわりに、正常に稼働しているサイトにこれらのセッションをフェイルオーバーし、処理中のトランザクションを再送信できます。
アプリケーション・コンティニュイティを有効にすると、データベースで次のことを実現できます。
-
メンテナンス中に新規または既存のいずれの作業でもエラーを報告しない
-
アクティブなデータベース・セッションを他の機能サービスにリダイレクトする
-
メンテナンス中およびメンテナンス後にデータベース・セッションを必要に応じて均衡化する
SRVCTLユーティリティ、Global Data Services制御ユーティリティ(GDSCTL)およびOracle Data Guard Brokerのdrain_timeout
およびstop_option
サービス属性を使用して、計画的メンテナンス中の排出動作を制御します。DBMS_SERVICE
パッケージは、基礎となるインフラストラクチャを提供します。
関連項目:
-
アプリケーション・コンティニュイティをさらに学習するには、Oracle Real Application Clusters管理およびデプロイメント・ガイドを参照してください
-
DBMS_SERVICE
についてさらに学習するには、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照 -
SRVCTLコマンド・リファレンスについては、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照
-
GDSCTLコマンド・リファレンスについては、Oracle Database Global Data Services概要および管理ガイドを参照
アプリケーション・コンティニュイティ・アーキテクチャ
アプリケーション・コンティニュイティの主なコンポーネントは、実行時、再接続およびリプレイです。
フェーズは次のとおりです。
-
通常の実行時
このフェーズでは、アプリケーション・コンティニュイティによって次のタスクが実行されます。
-
データベース・リクエストを識別する
-
ローカル・コールとデータベース・コールがリプレイ可能かどうかを判定する
-
リプレイの有効化と(必要に応じて)キューの管理を行うためのプロキシ・オブジェクトを作成する
-
データベース・リクエストが終了するか、リプレイが無効になるまで、元のコールとこれらのコールの検証を保持する
-
-
再接続
このフェーズは、リカバリ可能なエラーによってトリガーされます。アプリケーション・コンティニュイティによって次のタスクが実行されます。
-
データベース・リクエストのリプレイが有効であることを確認する
-
タイムアウトを管理する
-
データベースへの新しい接続を取得し、それが有効なデータベース・ターゲットであることを検証する
-
トランザクション・ガードを使用して、最後のトランザクションが正常にコミットされたかどうかを判定する(コミットされたトランザクションは再送信されない)
-
-
リプレイ
アプリケーション・コンティニュイティによって次のタスクが実行されます。
-
キューに保持されているコールをリプレイする
-
ユーザーが参照可能な結果の変更がリプレイ中に出現した場合は、リプレイを無効にする
-
コミットは許可しないが、(エラーが発生した)最後のリコールのコミットは許可する
-
リプレイに成功した後は、障害点からリクエストが続行されます。
関連項目:
-
アプリケーション・コンティニュイティについてさらに学習するには、Oracle Real Application Clusters管理およびデプロイメント・ガイドを参照してください
-
JDBCおよびアプリケーション・コンティニュイティについてさらに学習するには、Oracle Database JDBC開発者ガイドおよびOracle Database JDBC Java APIリファレンスを参照してください
自律型トランザクションの概要
自律型トランザクションは、メイン・トランザクションと呼ばれる他のトランザクションからコールできる独立したトランザクションです。コール側のトランザクションを一時停止して、自律型トランザクション内でSQL操作を実行し、その操作をコミットまたは取り消してから、コール側トランザクションを再開できます。
自律型トランザクションは、コール側トランザクションでコミットまたはロールバックするかどうかに関係なく、独立して実行する必要があるアクションを実装する場合に便利です。たとえば、株購入のトランザクションでは、全体的な株購入が成立するかどうかにかかわらず、顧客データをコミットする必要があります。また、トランザクション全体がロールバックされた場合でも、デバッグ表にエラー・メッセージを記録することも必要となります。
自律型トランザクションの特性は、次のとおりです。
-
自律型トランザクションでは、メイン・トランザクションによって加えられたがコミットされていない変更は取り扱わず、ロックやリソースをメイン・トランザクションと共有することもありません。
-
自律型トランザクション内の変更は、自律型トランザクションのコミット時に他のトランザクションに表示されるようになります。そのため、ユーザーはメイン・トランザクションのコミットを待機しなくても更新情報にアクセスできます。
-
自律型トランザクションで他の自律型トランザクションを開始できます。自律型トランザクションをコールできるレベル数には、リソース制限以外の制限はありません。
PL/SQLでは、自律型トランザクションは自律型スコープ内で実行されます(自律型スコープとは、プラグマAUTONOMOUS_TRANSACTION
でマークされたルーチンです)。このコンテキストでは、トップレベルの無名PL/SQLブロックおよびPL/SQLサブプログラムとPL/SQLトリガーが、ルーチンに含まれています。プラグマは、コンパイラにコンパイル・オプションの実行を指示するディレクティブです。プラグマAUTONOMOUS_TRANSACTION
によって、このプロシージャは実行時に親トランザクションから独立した新しい自律型トランザクションとして実行する必要があることが、データベースに指示されます。
次の図に、制御がメイン・ルーチン(MT)から自律型ルーチンに移り、再びメイン・ルーチンに戻ってくるまでのフローを示します。メイン・ルーチンはproc1
、自律型ルーチンはproc2
です。自律型ルーチンでは、制御がメイン・ルーチンに戻る前に、複数のトランザクション(AT1およびAT2)をコミットできます。
自律型ルーチンの実行可能セクションに入ると、メイン・ルーチンが一時停止します。この自律型ルーチンを終了すると、メイン・ルーチンが再開されます。
図10-4では、proc1
内部のCOMMIT
により、この文自体の作業のみでなく、そのセッション内で実行されたすべての保留中の作業が確定されます。ただし、proc2
内のCOMMIT
では、proc2
トランザクション内で実行された作業のみが確定されます。したがって、トランザクションAT1およびAT2内のCOMMIT
文は、MTトランザクションに影響を与えません。
関連項目:
自律型トランザクションの使用方法を学習するには、Oracle Database開発ガイドおよびOracle Database PL/SQL言語リファレンスを参照してください
分散トランザクションの概要
分散トランザクションとは、データベース・リンクと呼ばれるスキーマ・オブジェクトを使用し、分散データベースの複数の異なるノード上でデータを更新する、1つ以上の文を含むトランザクションのことです。
分散データベースは、分散システム内のデータベースの集合であり、アプリケーションには1つのデータソースとして認識されます。 データベース・リンクは、1つのデータベース・インスタンスが別のデータベース・インスタンスにログインする様子を記述します。
ローカル・データベースでのトランザクションとは異なり、分散トランザクションでは、複数データベース上にあるデータが変更されます。その結果、データベースではトランザクションでの変更のコミットやロールバックをアトミックな単位として処理する必要があるため、分散トランザクション処理はより複雑になります。トランザクション全体をコミットまたはロールバックする必要があります。Oracle Databaseはネットワーク全体でトランザクション制御を調整し、ネットワーク障害やシステム障害が発生した場合にもデータ整合性が保たれるようにする必要があります。
関連項目:
分散トランザクションの管理方法を学習するには、『Oracle Database管理者ガイド』を参照してください
2フェーズ・コミット
2フェーズ・コミット・メカニズムは、分散トランザクションに関係するすべてのデータベースが、そのトランザクション内の文のすべてをコミットするか、すべてを取り消すかのどちらか一方のみになるように保証するものです。このメカニズムでは、整合性制約、リモート・プロシージャ・コールおよびトリガーによって実行される暗黙的DMLも保護されます。
複数データベース間の2フェーズ・コミットでは、1つのデータベースで分散トランザクションが調整されます。開始ノードはグローバル・コーディネータと呼ばれます。このコーディネータによって、他のデータベースでコミットの準備ができているかどうかが確認されます。いずれかのデータベースで否定のレスポンスがあった場合は、トランザクション全体がロールバックされます。すべてのデータベースから肯定のレスポンスがあった場合は、コーディネータからメッセージがブロードキャストされ、各データベース上でコミットが確定されます。
2フェーズ・コミット・メカニズムは、分散トランザクションを発行するユーザーからは意識されません。事実、ユーザーは、トランザクションが分散していることも認識する必要はありません。トランザクションの終了を示すCOMMIT
文は、自動的に2フェーズ・コミット・メカニズムをトリガーします。データベース・アプリケーション本体に分散トランザクションを含めるのに、コーディングや複雑な構文の記述は必要ありません。
関連項目:
-
2フェーズ・コミットについて学習するには、Oracle Database管理者ガイドを参照してください。
インダウト・トランザクション
インダウト分散トランザクションは、システム障害やネットワーク障害によって2フェーズ・コミットが中断されたときに発生します。
たとえば、2つのデータベースから調整データベースにコミットの準備ができたことが報告されたものの、このメッセージの受信直後に調整データベース・インスタンスが失敗した場合などです。この場合、コミットの準備ができている2つのデータベースはハング状態となり、結果の通知を待機し続けます。
リカバラ(RECO
)・バックグラウンド・プロセスでは、インダウト分散トランザクションの結果が自動的に解決されます。障害が修復され、通信が再確立された後、各ローカルのOracleデータベースのRECO
プロセスが、関係するすべてのノード上でインダウト分散トランザクションを自動的にコミットするか、ロールバックします。
長時間にわたる障害が発生した場合、Oracle Databaseでは、各ローカル管理者が障害によって発生したインダウト分散トランザクションを手動でコミットまたは取り消すことができます。このオプションにより、ローカル・データベース管理者は、長時間にわたる障害によって無期限にロックされる可能性のあるリソースを解放できます。
あるデータベースを過去のある時点までリカバリする必要がある場合、データベースのリカバリ機能を使用すると、他のサイトのデータベース管理者が、自分のデータベースを過去のその同じ時点に戻すことができます。この操作により、グローバル・データベースは一貫した状態に保たれます。
関連項目:
-
インダウト・トランザクションの管理方法を学習するには、『Oracle Database管理者ガイド』を参照してください
脚注の凡例
脚注1:Oracle Real Application Clusters (Oracle RAC)の場合、論理トランザクションIDには、接頭辞としてデータベース・インスタンス番号が含まれます。