1

SQL Server 2012 に対して実行する C# OLTP アプリケーションがあります。データベースが AlwaysOn 可用性グループにある場合、フェールオーバーが発生した場合でも、アプリケーションを中断することなく実行したいと考えています。フェイルオーバーによって中断されたトランザクションから回復するために、C# SqlCommand オブジェクトを別のクラス (RetryableSqlCommand) でラップしました。このクラスは、フェイルオーバーに関連する例外 (接続が切断された、リモート トランザクションを強化できなかったなど) をキャッチし、それらを自動的に再試行します。指数関数的なバックオフ遅延の後。小さなテスト アプリでは、このコードは思いどおりに機能します。完全な OLTP アプリで中程度の負荷 (1 秒あたり数百トランザクション) で実行すると、データベースを手動でフェールオーバーするとエラーが発生します。

エラーは、1 つのマスタ レコードと 4 つの詳細レコードを挿入する、最も頻繁に呼び出されるストアド プロシージャの 1 つで常に発生します。ストアド プロシージャは常に、挿入されたマスター レコードと詳細レコードの ID を OUTPUT パラメーターとして返します。C# コードは次のようになります。

using (RetryableSqlCommand cmd = conn.CreateCommand())
{
  cmd.CommandText = "InsertComplexItem";
  cmd.CommandType = CommandType.StoredProcedure;
  // add sproc input parameters for master and detail records
  await cmd.ExecuteNonQueryAsync();

  // retrieve IDs of inserted records
  var masterId = (long)(cmd.Parameters["MasterId"].Value);   <-- InvalidCastException
  var detail1Id = (long)(cmd.Parameters["Detail1Id"].Value);
  var detail2Id = (long)(cmd.Parameters["Detail2Id"].Value);
  var detail3Id = (long)(cmd.Parameters["Detail3Id"].Value);
  var detail4Id = (long)(cmd.Parameters["Detail4Id"].Value);
}

上記の行で InvalidCastException が発生します。これは、デバッグ ログから判断したように、ID がストアド プロシージャから DBNull として返されているためです。私が知る限り、ストアド プロシージャはすべてのレコードを 1 つのトランザクションに挿入するため、このようなことは決して起こらないはずです。トランザクションが中断された場合、RetryableSqlCommand クラスによってキャッチされ、再試行される例外が存在するはずです。InvalidCastException の説明はありますか?

4

0 に答える 0