アプリケーションで次のエラーが発生しました。
このSQLTransactionは完了しました。使用できなくなりました
スタックトレースは以下に添付されています– Zombie Check
とRollback
について書かれています。
コードの間違いは何ですか?
注:このエラーは1回だけ発生しました。
[〜#〜]更新[〜#〜]
From MSDN --SqlTransaction.Rollback Method
接続が終了した場合、またはトランザクションがサーバー上ですでにロールバックされている場合、ロールバックはInvalidOperationExceptionを生成します。
From トランザクションのゾンビチェック-エラー
このエラーがさまざまなアプリケーションで表示されるのを私が見た最も頻繁な理由の1つは、アプリケーション間での共有SqlConnectionです。
[〜#〜]コード[〜#〜]
public int SaveUserLogOnInfo(int empID)
{
int? sessionID = null;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
transaction.Dispose();
transaction = null;
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
}
}
return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture);
}
スタックトレース
[〜#〜]参照[〜#〜]:
作業の一部をコンパイラに任せて、それをtry
/catch
/finally
でラップする必要があります。
また、Rollback
ステージで問題が発生した場合、またはサーバーへの接続が切断された場合、Commit
が例外をスローすることがあることを期待する必要があります。そのため、try
/catch
でラップする必要があります。
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
これは、 ロールバックメソッドのMSDNドキュメントページ から正確にコピーされます。
ゾンビ取引があるのではないかと心配しているようです。貼り付けた場合、問題ないようです。トランザクションが完了しました。これとは何の関係もありません。あなたがそれらを保持している場合はそれへの参照を削除し、それを忘れてください。
From MSDN --SqlTransaction.Rollback Method
接続が終了した場合、またはトランザクションがサーバー上ですでにロールバックされている場合、ロールバックはInvalidOperationExceptionを生成します。
新しい例外を再スローして、データが保存されていない可能性があることをユーザーに通知し、更新して確認するようにユーザーに依頼します
注:このエラーは1回だけ発生しました。
それなら多くを言うのは非常に難しいです。単に// Other Code
などは単に時間がかかり、すべてが殺されました。接続が切断されたか、ブロックしていたために管理者が意図的に接続を切断した可能性があります。
コードの間違いは何ですか?
それを過度に複雑にします。それははるかに簡単にすることができます:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using(var transaction = connection.BeginTransaction())
{
try
{
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
間違えるコードがはるかに少なくなります。
以下のコードを使用してこのエラーを再現できます。1000タスクを使用してSQLを実行し、約300タスクが正常に完了した後、_timeout error
_に関する多くの例外がExecuteNonQuery()
で発生し始めます。
次に、次のエラー_This SqlTransaction has completed
_がtransaction.RollBack();
で発生し、その呼び出しスタックにもZombieCheck()
が含まれます。
(1000タスクの単一プログラムで十分なプレッシャーがない場合は、コンパイルされた複数のexeファイルを同時に実行することも、複数のコンピューターを使用して1つのデータベースに対して実行することもできます。)
したがって、このエラーの原因の1つは、接続で問題が発生している可能性があることを推測します。次に、トランザクションエラーも発生します。
_Task[] tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
int j = i;
tasks[i] = new Task(() =>
ExecuteSqlTransaction("YourConnectionString", j)
);
}
foreach (Task task in tasks)
{
task.Start();
}
/////////////
public void ExecuteSqlTransaction(string connectionString, int exeSqlCou)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction();
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"select * from Employee";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
Console.WriteLine("Execute Sql to database."
+ exeSqlCou);
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
_
さらに、2回連続してコミットすると、この例外も呼び出されます。
_ transaction.Commit();
transaction.Commit();
_
または、コミット前に接続が閉じられた場合も、このエラーが発生します。
_ connection.Close();
transaction.Commit();
_
更新:
別の新しいテーブルを作成し、それに50万個のデータを挿入するのは奇妙だと思います。
次に、_select * from newtable
_ sqlで100000タスクを使用し、5つのプログラムを同時に実行します。今回はタイムアウトエラーが発生しますが、transaction.Rollback()
の場合、_SQLTransaction has completed error
_は呼び出されませんでした。
ただし、タイムアウトエラーが発生した場合は、catchブロックにジャンプし、catchブロックでtransaction.Commit()
を再度実行すると、_SQLTransaction has completed error
_が発生します。
私は一度このエラーを経験しましたが、行き詰まり、何が問題になっているのかわかりません。実際、私はレコードを削除していましたが、ストアドプロシージャではその子を削除していませんでした。特に、Stored Procedure
のdeleteステートメントはTransaction
境界内にありました。そのトランザクションコードをストアドプロシージャから削除し、この“This SqlTransaction has completed; it is no longer usable.”
のエラーの発生を取り除きました。
このメッセージは、トランザクションがすでに正常にコミットされているの後に例外をスローするコードを記述したためです。Commitメソッドまたは処理できます)の後に記述したコードを確認してください。 Try..Catchを使用し、最後にBlocks :)を使用します。