web-dev-qa-db-ja.com

「このSqlTransactionは完了しました。使用できなくなりました。」...構成エラー?

私はこれに約1日半取り組んでおり、多数のブログとWeb上のヘルプ記事を検索しました。 SOこのエラーに関連するいくつかの質問を見つけましたが、それらが私の状況にまったく当てはまるとは思いませんでした:P)。これを助けて説明できるかどうかわかりませんが...

リソースを追跡するための.NETアプリがあります。リソースを時間追跡システムと請求システムにコピーするエクスポート機能があります。これは、時間および請求データベースにリンクするストアドプロシージャにアクセスします。

最近、課金システムデータベースを新しいサーバーに移動しました(元のサーバー:Server 2003 SP2、SQL 2005、新しいサーバー:Server 2008 R2、SQL 2008 R2)。 2008データベースを指すリンクサーバーをセットアップしています。 2008サーバーを指すようにストアドプロシージャを更新した後、MSDTCおよびRPCに関するエラー(http://www.safnet.com/writing/tech/archives/2007/06/server_myserver.html)を受け取りました。リンクサーバーで 'rpc/rpc out'を有効にし、ネットワークアクセスを許可するようにMSDTCを設定しました( http://www.sqlwebpedia.com/content/msdtc-troubleshooting )。

エクスポート機能を実行しようとすると、上記の結果が得られます:「このSqlTransactionは完了しました。使用できなくなりました。」私にとって奇妙に思えるのは、(SSMSから)ストアドプロシージャを実行すると、正常に完了したということです。

誰もこれを見たことがありますか?構成で何かを見落としていませんか?私は同じページを続けて行きましたが、私が見つけた唯一のことは、MSDTCの変更を行った後に再起動しなかったことです(ここで説明します: http://social.msdn.Microsoft.com/forums/en -US/adodotnetdataproviders/thread/7172223f-acbe-4472-8cdf-feec80fd2e64 / )。

役立つ場合は、ストアドプロシージャの一部またはすべてを投稿できます...教えてください。

45
White Island

このエラーメッセージは「ゾンビトランザクション」が原因であると考えています。

トランザクションが2回コミットされる(または2回ロールバックされる、またはロールバックされてコミットされるなど)可能性のある領域を探します。 .Netコードは、SPが既にコミットした後、トランザクションをコミットしますか?最後に)節?

古いサーバーでエラー条件がヒットしなかった可能性があり、そのため、障害のある「ダブルロールバック」コードがヒットすることはありませんでした。新しいサーバーでis構成エラーが発生し、例外処理を介して障害のあるコードがヒットしている場合があります。

エラーコードにデバッグできますか?スタックトレースはありますか?

42
Phil Sandler

最近、新しい接続マネージャーでリファクタリングした後、これがありました。新しいルーチンがトランザクションを受け入れたため、バッチの一部として実行できましたが、問題はusingブロックにありました:

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  using (transaction.Connection)
  {
    using (transaction)
    {
      return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
    }
  }
}

外側の使用者が基礎となる接続を閉じているように見えるため、トランザクションをコミットまたはロールバックしようとすると、メッセージ"This SqlTransaction has completed; it is no longer usable."

私は使用を削除してカバーテストを追加し、問題はなくなりました。

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
}

トランザクションのコンテキスト内で接続を閉じている可能性のあるものを確認します。

6
Phil Cooper

私は同じ問題を抱えています。このエラーは、接続プーリングが原因で発生します。 2人以上のユーザーが存在する場合、システムは接続プーリングで接続と変換も再利用します。最初のユーザーがコミットまたはロールバックを実行すると、トランザクションは使用できなくなります。

4
Ademilso Peres

私は最近、同様の状況に出くわしました。 VS IDEバージョンでデバッグするには、デバッグから例外を開きます(Ctrl + D、E)-[スロー]列に対してすべてのチェックボックスをオンにし、デバッグモードでアプリケーションを実行します。テーブルの1つが新しいデータベースに適切にインポートされなかったため、内部SQL例外が接続を強制終了したため、このエラーが発生しました。

ストーリーの要点は、以前に動作していたコードが新しいデータベースでこのエラーを返す場合、データベーススキーマが見つからない問題である可能性があることです。

役に立てば幸い、HydTechie

3
HydPhani

私の場合、問題は、トランザクションに含まれるクエリの1つが例外を発生させ、例外が「正常に」処理されたにもかかわらず、トランザクション全体をロールバックすることができたことでした。

私の擬似コードは次のようなものでした:

var transaction = connection.BeginTransaction();
for(all the lines in a file)
{
     try{
         InsertLineInTable(); // INSERT statement might fail and throw an exception
     }
     catch {
         // notify the user about the error on line x and continue
     }
}

// Commit and Rollback will fail if one of the queries 
// in InsertLineInTable threw an exception
if(CheckTableForErrors())
{
    transaction.Commit();
}
else
{
    transaction.Rollback();
}
3
Loris

また、DBに対して.NETアプリから実行された長時間実行されているプロセスを確認します。たとえば、ログに次のように表示される、終了するのに十分な時間がないストアドプロシージャまたはクエリを呼び出す場合があります。

  • 実行タイムアウトが期限切れです。操作が完了する前にタイムアウト期間が経過したか、サーバーが応答していません。

    • このSqlTransactionは完了しました。もはや使用できません。

コマンドのタイムアウト設定を確認するトレース(プロファイラー)を実行して、DB側で何が起こっているかを確認してください...

1
Milan

ゾンビトランザクションを検出する方法を次に示します

_SqlTransaction trans = connection.BeginTransaction();

//some db calls here

if (trans.Connection != null) //Detecting zombie transaction
{
  trans.Commit();
}
_

SqlTransactionクラスを逆コンパイルすると、次のように表示されます

_public SqlConnection Connection
{
  get
  {
    if (this.IsZombied)
      return (SqlConnection) null;
    return this._connection;
  }
}
_

接続が閉じられた場合、transOPがゾンビになるため、Commitにはなりません。私の場合は、finallyブロック内にCommit()があり、接続はtryブロック内にあったためです。この配置により、接続が破棄され、ガベージコレクションが行われます。解決策は、代わりにCommitブロック内にtryを配置することでした。

0
Jeson Martajaya

私の場合、同じtry catchブロックでトランザクションをコミットした後、いくつかのコードがあります。エラーが発生すると、トランザクションのロールバックを含むブロックをキャッチするように実行される場合があります。同様のエラーが表示されます。たとえば、次のコード構造を見てください。

SqlTransaction trans = null;

try{
 trans = Con.BeginTransaction();
// your codes

  trans.Commit();
//your codes having errors

}
catch(Exception ex)
{
     trans.Rollback(); //transaction roll back
    // error message
}

finally
{ 
    // connection close
}

それが誰かを助けることを願っています:)

0
Amal P S