2

以下は、私が取り組んでいる2つのストアドプロシージャへの2つの呼び出しのコードです。オールオアナッシングアトミックトランザクションを実行するようにこれを設定したと思いましたが、2番目のストアドプロシージャ呼び出しでエラーが発生した場合でも、最初の呼び出しは実行されます。私はまだC#で​​これらを書くのは初めてなので、助けていただければ幸いです。どうも!

また、これが行っていることで奇妙だと思うことにも言及する必要があります。例外がスローされ、プログラムが「catch」ブロックに入った場合でも、「finally」ブロックのコードが実行されます。私の理解では、例外がスローされた場合、「catch」ブロックのコードだけが実行されます。

編集以下の応答のおかげで、catch / finalの混乱を修正し、ExecuteNonQuery()呼び出しを追加して、最初のストアドプロシージャも呼び出されるようにしました。ただし、最初のストアード・プロシージャーが呼び出されると、2番目のストアード・プロシージャーがその作業を実行する前に、最初に実行されるように呼び出される必要があります。これはアトミックトランザクションで実行できるものですか、それとも個別に実行する必要がありますか?

try
{
    cm = Dts.Connections["serverName"];
    sqlConn = (SqlConnection)cm.AcquireConnection(Dts.Transaction);
    sqlTrans = sqlConn.BeginTransaction("QueueUpdates");                                


    if (dummyIndicator.Equals("Y"))
    {
        string temp = retrievedMessage.Substring(203, 17);
        int newNumber = (int)(long.Parse(temp) / 777);

        SqlParameter newNum = new SqlParameter("@newNum", num.Value);
        SqlParameter oldNum = new SqlParameter("@oldNum", newNumber);

        sqlComm = new SqlCommand("DB.dbo.sp_UpdateNumber", sqlConn, sqlTrans);
        sqlComm.CommandType = CommandType.StoredProcedure;
        sqlComm.Parameters.Add(newNum);
        sqlComm.Parameters.Add(oldNum);
        sqlComm.Transaction = sqlTrans;
        sqlComm.ExecuteNonQuery();

    }

    //Update records according to queue messages
    sqlComm = new SqlCommand("DB.dbo.sp_AgentIdAprCheck", sqlConn, sqlTrans);
    sqlComm.CommandType = CommandType.StoredProcedure;
    sqlComm.Parameters.Add(num);
    sqlComm.Parameters.Add(addOrUpdate);
    sqlComm.Parameters.Add(companyCode);
    sqlComm.Parameters.Add(agentID);
    sqlComm.Parameters.Add(firstName);
    sqlComm.Parameters.Add(lastName);
    sqlComm.Parameters.Add(suffix);
    sqlComm.Parameters.Add(taxIdType);
    sqlComm.Parameters.Add(entityType);
    sqlComm.Parameters.Add(corporateName);
    sqlComm.Parameters.Add(outNewNumber);
    sqlComm.Parameters.Add(outCurrentNumber);
    sqlComm.Parameters.Add(outOperator);
    sqlComm.Parameters.Add(outDate);
    sqlComm.Parameters.Add(returnVal);
    sqlComm.ExecuteNonQuery();

    sqlTrans.Commit();

    if (addOrUpd.Equals("ADD")){recordsAdded++;}
    else{recordsUpdated++;}

}
catch (Exception ex)
{
    _sqlDataErrors++;
    swLog.WriteLine("Message not updated: " + retrievedMessage);
    swLog.WriteLine("Error: " + ex.ToString());
    sqlTrans.Rollback();
}
finally
{                                
    cm.ReleaseConnection(sqlConn);
}
4

3 に答える 3

1

まず、なぜそれtransactionがアトミックであることを強調するのですか?Transaction常にアトミックであるsmthを意味します。トランザクションは、すべてのブロックがコミットされるか、単一のブロックがコミットされないことを保証します。

あなたの場合のトランザクションの使用法を考えると-それはあなたのドメインロジックに依存します。選択はかなり簡単です:

  • 最初のspのみを実行し、2番目のspを実行できない場合は、単一のトランザクションを使用しないでください。
  • それが不可能な場合は、それを使用してください。

したがって、ドメインのルールとロジックについてさらに説明していただければ、どのシナリオが最適かをお伝えできます。

UPD わかりました。少し説明した後、問題はありません。確かに、特定の方法で実装して期待どおりの動作を得ることができるので、両方のspからのコマンドが1つのトランザクションで渡され、1つとして機能します。また、コードの改善の可能性についても指摘したいと思います。

  1. 例外処理をより具体的にすることができます。現在、問題が発生したときにロールバックしています。たとえば、-の場合、初期化される前にNullReferenceExceptionDts.Connections["serverName"];が発生し、ブロック内で、nullを処理する別の、を取得します。nullsqlTranscatchNullReferenceExceptionsqlTrans

  2. コードをデータベース固有のものとその他すべてに分割して、そのブロックの例外が常にデータベースレイヤーからの例外であることを確認できます。私は次のようなことをすることを意味します

    string temp = retrievedMessage.Substring(203, 17);

    int newNumber = (int)(long.Parse(temp) / 777);

潜在的に危険であり、例外をスローする可能性があるため、どこか別の場所にあります。

于 2012-08-27T06:34:44.217 に答える
0
  1. あなたは実際に最初の SP を実行していないようですが、それが原因で 2 つ目の問題が発生したのではないでしょうか?

  2. の目的はfinally、コード ブロックがどのように終了しても (通常の終了、例外、return ステートメントなど、すべてが を実行することになりますfinally)、常に実行されることです。したがって、リソースをクリアするために使用する必要があり、catch. Commit()ブロックの終わりの前の最後の行になるように呼び出しを移動し、ブロックからtry削除すると、期待どおりに機能し始めるはずです。ReleaseConnectioncatch

于 2012-08-27T00:13:36.357 に答える
0

finally ブロックは、(例外が発生するかどうかに関係なく) 実行されます。try ブロックの終了方法に関係なく、制御は常に finally ブロックに渡されます。

トランザクション コミット呼び出しを、finally ブロックから ExecuteQuery 呼び出しの後に移動します。また、最初のストアド プロシージャの if ブロックに sql コマンド オブジェクトを作成して保存しsqlCommますが、if ブロックの外側で、2 番目のストアド プロシージャの別の sql コマンド オブジェクトを作成し、同じsqlCommオブジェクトに保存します。最初のストアド プロシージャが実行されないようです。そこでロジックを変更する必要があるかもしれません。

于 2012-08-27T00:14:02.753 に答える