10

私はすでに多くの検索を行いましたが、ストレートなアンサーを見つけることができませんでした.

2 つのストアド プロシージャがあり、どちらも関数が DBContext オブジェクトにインポートされました。

  1. InsertA()
  2. InsertB()

それらをトランザクションに入れたい。(つまり、InsertB() が失敗した場合、InsertA() はロールバックされます)

それ、どうやったら出来るの?TransactionScope オブジェクトを宣言して、2 つのストアド プロシージャをラップすることはできますか?

ありがとう

4

2 に答える 2

15

次のように、操作をトランザクション スコープに登録する必要があります。

using(TransactionScope tranScope = new TransactionScope()) 
{
  InsertA();
  InsertB();

  tranScope.Complete();
}

エラーが発生すると、トランザクション スコープは自動的にロールバックされます。もちろん、例外を処理し、例外処理の設計で指示されていること (ログなど) を実行する必要があります。ただし、手動で を呼び出さない限り、スコープが終了するComplete()とトランザクションはロールバックされます。using

同じトランザクション スコープで他のデータベース接続を開かない限り、トランザクション スコープは分散トランザクションに昇格されません (こちらを参照)。

そうしないと、この操作に関係するすべてのサーバー (Web、最終的には中間層、SQL サーバー) でMSDTCを構成する必要があるため、これは知っておくことが重要です。したがって、トランザクションが分散トランザクションに昇格されない限り、問題はありません。

注: タイムアウトや分離レベルなどのトランザクション オプションを微調整するには、このTransactionScopeコンストラクターを参照してください。デフォルトの分離レベルはシリアライズ可能です。

追加サンプル: こちら.

于 2012-06-25T17:28:08.160 に答える
4

TransactionScope オブジェクトを使用するか、SqlConnection.BeginTransaction メソッドを使用できます。TransactionScope の使用には注意してください。別のデータベースでストアド プロシージャを呼び出すと、トランザクションが分散トランザクションにエスキュレートされる可能性があります。分散トランザクションは、リソースを大量に消費する可能性があります。

sqlConnection.BeginTransaction の使用方法...(http://msdn.microsoft.com/en-us/library/86773566.aspx)

private static void ExecuteSqlTransaction(string connectionString)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;

        // Start a local transaction.
        transaction = connection.BeginTransaction("SampleTransaction");

        // Must assign both transaction object and connection
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;

        try
        {
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')";
            command.ExecuteNonQuery();
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')";
            command.ExecuteNonQuery();

            // Attempt to commit the transaction.
            transaction.Commit();
            Console.WriteLine("Both records are written to database.");
        }
        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);
            }
        }
    }
}

TransactionScope の使用方法...(http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx)

// This function takes arguments for 2 connection strings and commands to create a transaction 
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the 
// transaction is rolled back. To test this code, you can connect to two different databases 
// on the same server by altering the connection string, or to another 3rd party RDBMS by 
// altering the code in the connection2 code block.
static public int CreateTransactionScope(
    string connectString1, string connectString2,
    string commandText1, string commandText2)
{
    // Initialize the return value to zero and create a StringWriter to display results.
    int returnValue = 0;
    System.IO.StringWriter writer = new System.IO.StringWriter();

    try
    {
        // Create the TransactionScope to execute the commands, guaranteeing
        // that both commands can commit or roll back as a single unit of work.
        using (TransactionScope scope = new TransactionScope())
        {
            using (SqlConnection connection1 = new SqlConnection(connectString1))
            {
                // Opening the connection automatically enlists it in the 
                // TransactionScope as a lightweight transaction.
                connection1.Open();

                // Create the SqlCommand object and execute the first command.
                SqlCommand command1 = new SqlCommand(commandText1, connection1);
                returnValue = command1.ExecuteNonQuery();
                writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

                // If you get here, this means that command1 succeeded. By nesting
                // the using block for connection2 inside that of connection1, you
                // conserve server and network resources as connection2 is opened
                // only when there is a chance that the transaction can commit.   
                using (SqlConnection connection2 = new SqlConnection(connectString2))
                {
                    // The transaction is escalated to a full distributed
                    // transaction when connection2 is opened.
                    connection2.Open();

                    // Execute the second command in the second database.
                    returnValue = 0;
                    SqlCommand command2 = new SqlCommand(commandText2, connection2);
                    returnValue = command2.ExecuteNonQuery();
                    writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
                }
            }

            // The Complete method commits the transaction. If an exception has been thrown,
            // Complete is not  called and the transaction is rolled back.
            scope.Complete();

        }

    }
    catch (TransactionAbortedException ex)
    {
        writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
    }
    catch (ApplicationException ex)
    {
        writer.WriteLine("ApplicationException Message: {0}", ex.Message);
    }

    // Display messages.
    Console.WriteLine(writer.ToString());

    return returnValue;
}
于 2012-06-25T17:58:21.337 に答える