2009-04-24 15 views
3

私はSystem.Transactionsの機能を知ることができるように、すばやいダミーアプリを作ろうとしています。このアプリケーションは、2つの異なるSQLExpress DBと対話します。コンポーネントサービスでトランザクション統計を取得すると、2番目の接続が開かれたときにouterScopeでトランザクションが開始されます。 failOuterがtrueの場合、トランザクションはアボートされますが、例外はスローされません。 failInnerがtrueの場合、TransactionAbortedExceptionがスローされます。 MSDNからTransactionScopeを理解しようとしています

アプリケーションは、それがトランザクションで実行したいすべての作業を完了したら、あなたはトランザクションのコミットを受け入れ可能であることをトランザクションマネージャに通知するために、一度だけ完全なメソッドを呼び出す必要があります。 usingブロックの最後のステートメントとしてCompleteを呼び出すことは、非常に良い習慣です。

このメソッドの呼び出しに失敗すると、トランザクションマネージャーはこれをシステム障害、またはトランザクションのスコープ内でスローされた例外と解釈するため、トランザクションを中止します。

スコープがトランザクションを作成し、トランザクションがアボートされると、TransactionAbortedExceptionがスローされます。私は私のトランザクション統計は毎回中止されたトランザクションを示しているので、私はfailOuterと私のアプリをtrueに設定し実行する私のouterScopeがTransactionAbortedExceptionを投げることを期待することに基づいて

。トランザクションが中断しても例外がスローされないので、私のメソッドはtrueを返します。私が内部取引を中止しない限り、それは私が期待するように動作します。どのような明確化が最も高く評価されるだろう。

public bool CreateNestedTransaction(bool failOuter, bool failInner) 
    { 
     try 
     { 
      using (TransactionScope outerScope = new TransactionScope()) 
      { 

       /* Perform transactional work here */ 
       using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1")) 
       { 
        SqlCommand myCommand = new SqlCommand(); 
        myConnection.Open(); 
        myCommand.Connection = myConnection; 

        myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)"; 
        myCommand.ExecuteNonQuery(); 
       } 


       using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1")) 
       { 
        SqlCommand myCommand = new SqlCommand(); 
        myConnection.Open(); 
        myCommand.Connection = myConnection; 

        myCommand.CommandText = "update test set Value = Value"; 
        myCommand.ExecuteNonQuery(); 
       } 

       using (TransactionScope innerScope = new TransactionScope()) 
       { 
        using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2")) 
        { 
         SqlCommand myCommand = new SqlCommand(); 
         myConnection.Open(); 
         myCommand.Connection = myConnection; 

         myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)"; 
         myCommand.ExecuteNonQuery(); 
        } 
        if (failInner == false) { innerScope.Complete(); } 
       } 

       if (failOuter == false) { outerScope.Complete(); } 
      } 
     } 

     catch (TransactionAbortedException) 
     { 
      return false; 
     } 

     return true; 
    } 

答えて

7

通常、TransactionScopeがスコープから外れて破棄される前に、TransactionScope.Complete()を呼び出さないと例外がスローされません。トランザクションは静かにロールバックします。

外側のTransactionScopeでCompleteを呼び出そうとしていて、内側のTransactionScopeがすでに失敗しているため、例外が発生する可能性があります。例外が発生します。

それは意味がありますか?

あなたの外側のトランザクションが中止された場合、いくつかの操作を実行したい場合は、このような何か試してみてください:私は一般的な使用のためのクリーナーパターンは常に(完全を呼び出すことであろうと思いますけれども

// Inside each using TransactionScope(), hhok up the current transaction completed event 
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted); 

// handle the event somewhere else 
void Current_TransactionCompleted(object sender, TransactionEventArgs e) 
{ 
    // check the status of the transaction 
    if(e.Transaction.TransactionInformation.Status == TransactionStatus.Aborted) 
    // do something here 
} 

を)あなたの内側トランザクションの失敗に特有の処理を実行する場合は、TransactionScopeを使用し、結果の例外を処理します。

+0

はい、意味があります。私はMSDNの最後の行が私を捨てていたと思う。トランザクションが中止され、例外が発生するのを見ていました。説明ありがとう!私の外側の例外が異常終了したかどうかを知る方法はありますか?私はその場合にfalseを返す。 –

+0

Hmm興味深い質問 - わからない!私は家に帰って、あなたに知らせるときにそれをチェックします:) –

+0

はい、それは私が一般的に使用するパターンではありませんが、それを行う方法があるように見えます。 –

関連する問題