ヘッダーをスキップ
Oracle® Data Provider for .NET開発者ガイド
12c リリース1(12.1)
B72971-07
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

論理破損を防ぐためのトランザクション・ガードの使用

トランザクション・ガードを使用すると、計画済および計画外の停止時や送信が繰り返された場合に、ODP.NETアプリケーションで実行を1回以下にすることができます。

ODP.NETは、論理トランザクション・オブジェクトOracleLogicalTransactionを返します。これは、停止に続くデータベース・セッションでオープンになっている最終トランザクションの結果を判断するために使用されます。トランザクション・ガードを使用しないと、アプリケーションが停止の後に操作を実行しようとして、トランザクションが重複してコミットされ論理破損が発生する可能性があります。

停止後にアプリケーションをリカバリする際の従来の問題の1つは、継続性のないコミット・メッセージがクライアントに戻されることでした。クライアントとサーバーの間が中断されると、クライアントには通信が失敗したことを示す(リカバリ可能エラーとも呼ばれる)エラー・メッセージが示されます。このエラーは、送信でコミット操作が実行されたかどうかや、すべての予測されるコミットの実行中に完了まで手続きコールを実行したかどうかをアプリケーションに通知しません。エラーはセッション・ステート変更または断続的な障害も示しません。トランザクションがコミットされたかどうか、完全に完了したかどうか、クライアントは確認できないままです。

このリカバリ可能エラーによって、エンド・ユーザーやアプリケーションがリプレイを試し、重複したトランザクションが送信されることで、その他の論理破損が引き起こされます。トランザクションは、非トランザクション状態が不正確な場合、またはそのトランザクションがコミットされている場合は、有効に再送信できません。コミットされているが完了していないコールの処理を続けると、誤った状態のデータベース・セッションがアプリケーションで使用されることになります。

トランザクション・ガードでは、ODP.NETによって自動的かつ透過的に基準化された方法で、アプリケーションでのトランザクションの重複を解消します。ODP.NETは論理トランザクション・オブジェクトを使用して、オープンになっている最終トランザクションを識別します。実行時に、Oracleは自動的にトランザクション・ステータスを保持します。コミット時に、論理トランザクション・オブジェクトが永続します。データベースでは、管理者が設定している保存期間にわたり、コミット後の論理トランザクション・ステータスが維持されます。ODP.NETは論理トランザクション・オブジェクトを使用して、次のトランザクションを追跡できます。

ノード、ネットワーク、データベースなどで障害が発生した場合、ODP.NETアプリケーションは論理トランザクション・オブジェクトを使用してステータスを問い合せることで、そのトランザクションがコミットされたかどうかを判断できます。コミットされていなければ、ODP.NETアプリケーションは、トランザクションの状態を認識し、リカバリ可能かどうか、戻されたOracleExceptionを通じて再試行できるかどうかを判断できます。これにより、ODP.NETアプリケーションでは、コミットされていない場合は再送信するなど、適切な操作が行われます。


注意:

  • ODP.NET管理対象外ドライバは、トランザクション・ガードおよびリカバリ可能エラー検出機能をサポートしています。ただし、ODP.NET管理対象ドライバはいずれの機能も現在サポートしていません。

  • トランザクション・ガードは、ローカル・トランザクションのみをサポートしています。分散トランザクションはサポートしていません。


トランザクション・ガードの機能は、Oracleサービスレベル構成のCOMMIT_OUTCOME設定によって有効または無効にします。デフォルトでは無効です。この設定はデータベースを停止せずに変更できます。新しい設定は、このサービスに対して作成された新規接続にのみ適用されます。

次に、ODP.NETトランザクション・ガードのアプリケーション・シナリオの例を示します。

ODP.NETアプリケーションは、FANダウン・イベントまたはエラーを受信します。FANは、中断されたセッションを自動的に強制終了し、アプリケーションはOracleExceptionを受信します。エラーを透過的に処理するために作成されたトランザクション・ガード・アプリケーションは、次のことを実行します。

  1. OracleException.IsRecoverableプロパティの値を確認します。値がtrueの場合、アプリケーションは、次の手順で説明するとおり、現在のトランザクション・ステータスに基づいて既存のトランザクションを再送信できます。値がfalseの場合、アプリケーションは、現在のトランザクションのロールバック、再実行および再送信を行う必要があります。

  2. 失敗したセッションから、アプリケーションが最後の論理トランザクションを受け取ります。

    OracleConnection.OracleLogicalTransaction

  3. アプリケーションはトランザクション・ステータスOracleLogicalTransaction.GetOutcome()を取得します。


    注意:

    トランザクションのステータスを取得するデータベース・ユーザーには、DBMS_APP_CONTパッケージのEXECUTE権限を付与する必要があります。

  4. トランザクション・ステータスは、結果について次の2つの側面を示します。

    • 正常にコミットされたかどうかOracleLogicalTransaction.Committed

    • 正常に完了したかどうかOracleLogicalTransaction.UserCallCompleted

Committedの値 UserCallCompletedの値 結果
True True トランザクションは正常に完了しました。結果をアプリケーションに戻すことができます。
False False トランザクションは正常に完了していません。そのトランザクションをアプリケーションで再送信することができます。
True False トランザクションはコミットされましたが、アプリケーションで期待どおりに続行されていない未完了の状態(行数やネスト済のPL/SQLロジックなど)が含まれている可能性があります。

サンプル・コード

using System;
using Oracle.DataAccess.Client;
 
class Test
{
  static void Main()
  {
    bool bReadyToCommit = false;
    string constr = "user id=scott;password=tiger;data source=inst1";
    OracleConnection con = new OracleConnection(constr);
    OracleTransaction txn = null;
    OracleCommand cmd = null;
 
    try
    {
      con.Open();
      txn = con.BeginTransaction();
      cmd = new OracleCommand(con, "update emp set dept=10 where empno=7654");
      cmd.ExecuteNonQuery();
      bReadyToCommit = true;
    }
    catch(Exception ex)
    {
      Console.WriteLine(ex.ToString());
    }
 
    try
    {
      if (bReadyToCommit)
        txn.Commit();
    }
    catch(Exception ex)
    {
      if (ex.IsRecoverable)
      {
        OracleLogicalTransaction olt = con.OracleLogicalTransaction;
        olt.GetOutcome(); // or olt.GetOutcome("scott", "tiger", "inst1");
         
        if (!olt.Committed && !olt.UserCallCompleted)
        {
          // any chosen processing here if a retry is desired.
        }
        else
        {
        // transaction committed, but was not full completed
        }
      }
      else
      {
        // Not recoverable transaction. Rollback (and re-execute).
      }
    }
    finally
    {
      txn.Dispose();
      cmd.Dispose();
      con.Dispose();
    }
  }
}

関連項目: