System.Transactionsの詳細を学ぶことができるように、簡単なダミーアプリを作成しようとしています。このアプリは、2つの異なるSQLExpressDBと相互作用します。コンポーネントサービスでトランザクション統計を取得すると、2番目の接続が開かれたときにouterScopeでトランザクションが開始されていることがわかります。failOuterがtrueの場合、トランザクションは中止されますが、例外はスローされません。failInnerがtrueの場合、TransactionAbortedExceptionがスローされます。
MSDNから:
アプリケーションがトランザクションで実行したいすべての作業を完了したら、Completeメソッドを1回だけ呼び出して、トランザクションをコミットできることをトランザクションマネージャーに通知する必要があります。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;
}