0

ASP.Net で送信ルーチンを実行しています。問題は、try-catch ブロックでコードをデバッグしているときに、ユーザーがエラーに遭遇した場合、SQL トランザクションがロールバックしないことです。

このサブミット ルーチンを途中で中断すると、SQL Server 2008 が完全にハングします。SSMS からでも Select/Insert 操作を実行できません。最後に、トランザクションをロールバックするために SQL Server を再起動する必要があります。

提出用コード:

SqlConnection conn = Db.getConn();
if (conn.State == ConnectionState.Closed) conn.Open();

SqlTransaction trn;
trn = conn.BeginTransaction();

SqlCommand sqlCmd = new SqlCommand("", conn);
sqlCmd.Transaction = trn;

try
{
    string query = GetQuery(); // works fine
    sqlCmd.CommandText = query;

    sqlCmd.ExecuteNonQuery();


    using (SqlBulkCopy bcp = new SqlBulkCopy(conn,SqlBulkCopyOptions.Default, trn))        
        {
            bcp.ColumnMappings.Add("FaYear", "FaYear");
            bcp.ColumnMappings.Add("CostCode", "CostCode");
            bcp.ColumnMappings.Add("TokenNo", "TokenNo");

            bcp.DestinationTableName = "ProcessTokenAddress";
            bcp.WriteToServer(globaltblAddress.DefaultView.ToTable());
        }
    trn.commit();
}
catch (SqlException ex)
{
   trn.Rollback();
}

注:ここでコードを書いているときに、ExceptionではなくSqlExceptionをキャッチしたことに気付きました。それがエラーの原因ですか?ふー?

重要: Page_UnLoad または予期しない状況を処理できるその他のイベント ハンドラーでトランザクションをロールバックする必要がありますか (たとえば、トランザクションの進行中にユーザーがブラウザーを閉じる、ユーザーが [戻る] ボタンを押すなど)。

4

1 に答える 1

1

まず、.Net では、何度も再利用する単一の開いている接続を維持するべきではありません。この結果は、実際に経験していることとまったく同じです。接続を閉じる必要がある状況では、そうではありません

次に、接続が実装されIDisposableます。これは、usingステートメント内、または接続を明示的に閉じるtry-catchを持つブロック内で作成および使用する必要があることを意味します。クラス自体が接続を実装して存続期間保持し、破棄されたときに接続を閉じるfinallyクラスがある場合、この規則を破ることができます。IDisposable

常に接続を開いたり閉じたりしないことで効率が向上していると考えたくなるかもしれません。実際、.Net は接続プーリングを処理するため、誤解される可能性があります。標準的な方法は、接続オブジェクトを開くのではなく、接続文字列を渡すことです。新しい接続を返すクラスで接続文字列をラップできますが、開いた接続を維持しないでください。そうすることで、経験したようなエラーが発生する可能性があります。

代わりに、次のことを行います。

  1. usingステートメントを使用します。これにより、接続を作成して使用した後、接続が適切にクリーンアップされます。

    using (SqlConnection conn = Db.getConn()) {
        conn.Open();
        // your code here
    }
    
  2. 接続が開いているかどうかを確認する必要があるという事実は、問題を示しています。これをしないでください。代わりに、毎回新しく作成されたDb接続を渡すようにクラスのコードを変更してください。そうすれば、状態が閉じていることを確信でき、自信を持って開くことができます。または、クラスで接続を開きますが、メソッドに名前を付けて、接続が開かれることを示します。(メソッド名とクラス名は省略しないようにしてください。)DbGetNewOpenConnection

  3. エラーをお勧めしますthrow。それをログに記録してスローしないことは可能なオプションですが、ユーザーが結果を期待してコンピューターの前に座っている状況では、単にエラーを飲み込むことは正しいアクションではありません。ユーザーに知らせますか?例外情報をユーザーに渡す何らかの手段が必要です。黙って飲み込むよりも、例外をまったく処理しない方がよいでしょう。

最後にgetConn()、C# コミュニティで見られ、Microsoft が推奨する通常の大文字化の慣行に従わないスタイル ノートがあります。クラスのパブリック メソッドは、大文字で始まる必要があります: GetConn().

于 2017-04-20T21:32:04.413 に答える