트랜잭션 범위를 사용하여 암시적 트랜잭션 구현Implementing an Implicit Transaction using Transaction Scope

TransactionScope 클래스는 트랜잭션 자체와 상호 작용할 필요 없이 코드 블록을 트랜잭션에 참여하는 것으로 표시하는 단순한 방법을 제공합니다.The TransactionScope class provides a simple way to mark a block of code as participating in a transaction, without requiring you to interact with the transaction itself. 트랜잭션 범위는 자동으로 앰비언트 트랜잭션을 선택하고 관리할 수 있습니다.A transaction scope can select and manage the ambient transaction automatically. 사용하기 쉽고 효율적이므로 트랜잭션 애플리케이션을 개발할 때는 TransactionScope 클래스를 사용하는 것이 좋습니다.Due to its ease of use and efficiency, it is recommended that you use the TransactionScope class when developing a transaction application.

또한 트랜잭션을 사용하여 명시적으로 리소스를 등록할 필요가 없습니다.In addition, you do not need to enlist resources explicitly with the transaction. System.Transactions 리소스 관리자(예: SQL Server 2005)는 범위에서 만든 앰비언트 트랜잭션이 있는지 감지하고 자동으로 등록할 수 있습니다.Any System.Transactions resource manager (such as SQL Server 2005) can detect the existence of an ambient transaction created by the scope and automatically enlist.

트랜잭션 범위 만들기Creating a transaction scope

다음 샘플에서는 TransactionScope 클래스의 단순한 사용을 보여 줍니다.The following sample shows a simple usage of the TransactionScope class.

// 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);
    }

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

    return returnValue;
}
'  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.
Public Function CreateTransactionScope( _
  ByVal connectString1 As String, ByVal connectString2 As String, _
  ByVal commandText1 As String, ByVal commandText2 As String) As Integer

    ' Initialize the return value to zero and create a StringWriter to display results.
    Dim returnValue As Integer = 0
    Dim writer As System.IO.StringWriter = 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 scope As New TransactionScope()
            Using connection1 As 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.
                Dim command1 As SqlCommand = 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 connection2 As 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
                    Dim command2 As SqlCommand = New SqlCommand(commandText2, connection2)
                    returnValue = command2.ExecuteNonQuery()
                    writer.WriteLine("Rows to be affected by command2: {0}", returnValue)
                End Using
            End Using

        ' The Complete method commits the transaction. If an exception has been thrown,
        ' Complete is called and the transaction is rolled back.
        scope.Complete()
        End Using
    Catch ex As TransactionAbortedException
        writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message)
    End Try

    ' Display messages.
    Console.WriteLine(writer.ToString())

    Return returnValue
End Function

TransactionScope 개체를 만들면 트랜잭션 범위가 시작 됩니다.The transaction scope is started once you create a new TransactionScope object. 코드 샘플에 나와 있는 것 처럼 using 문으로 범위를 만드는 것이 좋습니다.As illustrated in the code sample, it is recommended that you create scopes with a using statement. using 문은 C# 및의 Visual Basic에서 사용할 수 있으며,try...finally블록과 같은 방식으로 작동 하 여 범위가 제대로 삭제 되었는지 확인 합니다.The using statement is available both in C# and in Visual Basic, and works like a try...finally block to ensure that the scope is disposed of properly.

TransactionScope를 시작하면 트랜잭션 관리자는 참가할 트랜잭션을 결정합니다.When you instantiate TransactionScope, the transaction manager determines which transaction to participate in. 결정 되 면 범위는 항상 해당 트랜잭션에 참여 합니다.Once determined, the scope always participates in that transaction. 이러한 결정은 앰비언트 트랜잭션이 있는지 여부와 생성자에 TransactionScopeOption 매개 변수의 값을 기준으로 합니다.The decision is based on two factors: whether an ambient transaction is present and the value of the TransactionScopeOption parameter in the constructor. 앰비언트 트랜잭션은 코드가 실행되는 트랜잭션입니다.The ambient transaction is the transaction within which your code executes. Transaction 클래스의 정적 Transaction.Current 속성을 호출 하 여 앰비언트 트랜잭션에 대 한 참조를 가져올 수 있습니다.You can obtain a reference to the ambient transaction by calling the static Transaction.Current property of the Transaction class. 이 매개 변수를 사용 하는 방법에 대 한 자세한 내용은이 항목의 TransactionScopeOption를 사용 하 여 트랜잭션 흐름 관리 섹션을 참조 하십시오.For more information on how this parameter is used, see the Managing transaction flow using TransactionScopeOption section of this topic.

트랜잭션 범위 완료Completing a transaction scope

애플리케이션이 트랜잭션에서 수행할 작업을 모두 완료하면 Complete 메서드를 한 번만 호출하여 트랜잭션 커밋이 허용됨을 트랜잭션 관리자에게 알려야 합니다.When your application completes all the work it wants to perform in a transaction, you should call the Complete method only once to inform the transaction manager that it is acceptable to commit the transaction. Complete 호출을 using 블록의 마지막 문으로 배치하는 것이 좋습니다.It is very good practice to put the call to Complete as the last statement in the using block.

트랜잭션 관리자가이를 시스템 오류로 해석 하거나 트랜잭션 범위 내에서 throw 된 예외와 동일 하 게 해석 되므로이 메서드를 호출 하지 못하면 트랜잭션이 중단 됩니다.Failing to call this method aborts the transaction, because the transaction manager interprets this as a system failure, or equivalent to an exception thrown within the scope of the transaction. 그러나 이 메서드를 호출해도 반드시 트랜잭션이 커밋되지는 않습니다.However, calling this method does not guarantee that the transaction wil be committed. 단순히 트랜잭션 관리자에 게 상태를 알리는 방법입니다.It is merely a way of informing the transaction manager of your status. Complete 메서드를 호출한 후에는 더 이상 Current 속성을 통해 앰비언트 트랜잭션에 액세스할 수 없으며 액세스를 시도하면 예외가 throw됩니다.After calling the Complete method, you can no longer access the ambient transaction by using the Current property, and attempting to do so will result in an exception being thrown.

TransactionScope 개체가 처음으로 트랜잭션을 만든 경우 실제로 트랜잭션 관리자가 트랜잭션을 커밋하는 작업은 using 블록의 마지막 코드 줄 이후에 발생합니다.If the TransactionScope object created the transaction initially, the actual work of committing the transaction by the transaction manager occurs after the last line of code in the using block. 트랜잭션을 만들지 않은 경우 CommittableTransaction 개체의 소유자가 Commit를 호출할 때마다 커밋이 발생 합니다.If it did not create the transaction, the commit occurs whenever Commit is called by the owner of the CommittableTransaction object. 이 시점에서 트랜잭션 관리자는 리소스 관리자를 호출 하 여 TransactionScope 개체에서 Complete 메서드가 호출 되었는지 여부에 따라 커밋 또는 롤백을 알립니다.At that point the transaction manager calls the resource managers and informs them to either commit or rollback, based on whether the Complete method was called on the TransactionScope object.

using 문은 예외가 발생하는 경우에도 Dispose 개체의 TransactionScope 메서드가 호출되도록 합니다.The using statement ensures that the Dispose method of the TransactionScope object is called even if an exception occurs. Dispose 메서드는 트랜잭션 범위의 끝을 표시합니다.The Dispose method marks the end of the transaction scope. 이 메서드를 호출한 후에 발생 하는 예외는 트랜잭션에 영향을 주지 않을 수 있습니다.Exceptions that occur after calling this method may not affect the transaction. 또한 이 메서드는 앰비언트 트랜잭션을 이전 상태로 복원합니다.This method also restores the ambient transaction to it previous state.

범위가 트랜잭션을 만들면 TransactionAbortedException이 throw되고 트랜잭션이 중단됩니다.A TransactionAbortedException is thrown if the scope creates the transaction, and the transaction is aborted. 트랜잭션 관리자가 커밋 결정에 도달할 수 없는 경우 TransactionInDoubtException이 throw됩니다.A TransactionInDoubtException is thrown if the transaction manager cannot reach a Commit decision. 트랜잭션이 커밋되면 예외가 throw되지 않습니다.No exception is thrown if the transaction is committed.

트랜잭션 롤백Rolling back a transaction

트랜잭션을 롤백하려면 트랜잭션 범위 내에서 Complete 메서드를 호출하면 안 됩니다.If you want to rollback a transaction, you should not call the Complete method within the transaction scope. 예를 들어 범위 내에서 예외를 throw할 수 있습니다.For example, you can throw an exception within the scope. 범위가 참여하는 트랜잭션이 롤백됩니다.The transaction in which it participates in will be rolled back.

TransactionScopeOption를 사용 하 여 트랜잭션 흐름 관리Managing transaction flow using TransactionScopeOption

다음 예제의 TransactionScope 메서드와 같이 자체 범위를 사용하는 메서드 내의 RootMethod를 사용하는 메서드를 호출하여 트랜잭션 범위를 중첩할 수 있습니다.Transaction scope can be nested by calling a method that uses a TransactionScope from within a method that uses its own scope, as is the case with the RootMethod method in the following example,

void RootMethod()
{
    using(TransactionScope scope = new TransactionScope())
    {
        /* Perform transactional work here */
        SomeMethod();
        scope.Complete();
    }
}

void SomeMethod()
{
    using(TransactionScope scope = new TransactionScope())
    {
        /* Perform transactional work here */
        scope.Complete();
    }
}

맨 위의 트랜잭션 범위를 루트 범위라고 합니다.The top-most transaction scope is referred to as the root scope.

TransactionScope 클래스는 범위의 트랜잭션 동작을 정의하는 TransactionScopeOption 형식의 열거를 받아들이는 여러 개의 오버로드된 생성자를 제공합니다.The TransactionScope class provides several overloaded constructors that accept an enumeration of the type TransactionScopeOption, which defines the transactional behavior of the scope.

TransactionScope 개체에는 다음 세 가지 옵션이 있습니다.A TransactionScope object has three options:

  • 앰비언트 트랜잭션에 참여하거나 앰비언트 트랜잭션이 없는 경우 새로 만듭니다.Join the ambient transaction, or create a new one if one does not exist.

  • 새 루트 범위로 설정합니다. 즉, 새 트랜잭션을 시작하고 해당 트랜잭션이 자체 범위 내부의 새 앰비언트 트랜잭션이 되도록 합니다.Be a new root scope, that is, start a new transaction and have that transaction be the new ambient transaction inside its own scope.

  • 트랜잭션에 참여하지 않습니다.Not take part in a transaction at all. 이렇게 하면 앰비언트 트랜잭션이 없습니다.There is no ambient transaction as a result.

Required를 사용하여 범위를 인스턴스화하고 앰비언트 트랜잭션이 있는 경우 범위가 해당 트랜잭션에 참여합니다.If the scope is instantiated with Required, and an ambient transaction is present, the scope joins that transaction. 반면 앰비언트 트랜잭션이 없으면 범위가 새 트랜잭션을 만들고 루트 범위가 됩니다.If, on the other hand, there is no ambient transaction, then the scope creates a new transaction, and become the root scope. 이 설정은 기본값입니다.This is the default value. Required를 사용하는 경우 루트이든 앰비언트 트랜잭션에 참여하든 관계없이 범위 내부의 코드가 다르게 동작할 필요가 없습니다.When Required is used, the code inside the scope does not need to behave differently whether it is the root or just joining the ambient transaction. 두 경우에서 모두 동일하게 작동해야 합니다.It should operate identically in both cases.

RequiresNew를 사용하여 범위를 인스턴스화하는 경우 항상 루트 범위가 됩니다.If the scope is instantiated with RequiresNew, it is always the root scope. 새 트랜잭션을 시작하고 해당 트랜잭션이 범위 내부의 새 앰비언트 트랜잭션이 됩니다.It starts a new transaction, and its transaction becomes the new ambient transaction inside the scope.

Suppress를 사용하여 범위를 인스턴스화하는 경우 앰비언트 트랜잭션이 있는지 여부에 관계없이 트랜잭션에 참여하지 않습니다.If the scope is instantiated with Suppress, it never takes part in a transaction, regardless of whether an ambient transaction is present. 이 값으로 인스턴스화된 범위는 항상 null을 앰비언트 트랜잭션으로 사용합니다.A scope instantiated with this value always have null as its ambient transaction.

위의 옵션은 다음 표에 요약되어 있습니다.The above options are summarized in the following table.

TransactionScopeOptionTransactionScopeOption 앰비언트 트랜잭션Ambient Transaction 범위의 참여 여부The scope takes part in
필요한 공간Required 아니요No 새 트랜잭션(루트가 됨)New Transaction (will be the root)
RequiresNewRequires New 아니요No 새 트랜잭션(루트가 됨)New Transaction (will be the root)
SuppressSuppress 아니요No 트랜잭션 없음No Transaction
필요한 공간Required Yes 앰비언트 트랜잭션Ambient Transaction
RequiresNewRequires New Yes 새 트랜잭션(루트가 됨)New Transaction (will be the root)
SuppressSuppress Yes 트랜잭션 없음No Transaction

TransactionScope 개체가 기존의 앰비언트 트랜잭션에 참여하는 경우 범위가 트랜잭션을 중단하지 않으면 범위 개체를 삭제해도 트랜잭션이 종료되지 않을 수 있습니다.When a TransactionScope object joins an existing ambient transaction, disposing of the scope object may not end the transaction, unless the scope aborts the transaction. 루트 범위로 앰비언트 트랜잭션을 만든 경우 루트 범위가 삭제되는 경우에만 트랜잭션에서 Commit이 호출됩니다.If the ambient transaction was created by a root scope, only when the root scope is disposed of, does Commit get called on the transaction. 수동으로 트랜잭션을 만든 경우 작성자가 트랜잭션을 중단하거나 커밋할 때 트랜잭션이 종료됩니다.If the transaction was created manually, the transaction ends when it is either aborted, or committed by its creator.

다음 예제에서는 각각 다른 TransactionScope 값으로 인스턴스화된 세 가지 중첩 범위 개체를 만드는 TransactionScopeOption 개체를 보여 줍니다.The following example shows a TransactionScope object that creates three nested scope objects, each instantiated with a different TransactionScopeOption value.

using(TransactionScope scope1 = new TransactionScope())
//Default is Required
{
    using(TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Required))
    {
        //...
    }

    using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew))   
    {
        //...  
    }
  
    using(TransactionScope scope4 = new TransactionScope(TransactionScopeOption.Suppress))
    {
        //...  
    }
}

이 예제에서는 scope1를 사용하여 새 범위(Required)를 만드는 앰비언트 트랜잭션이 없는 코드 블록을 보여 줍니다.The example shows a code block without any ambient transaction creating a new scope (scope1) with Required. scope1 범위는 새 트랜잭션(Transaction A)을 만들 때 루트 범위이며 Transaction A를 앰비언트 트랜잭션으로 설정합니다.The scope scope1 is a root scope as it creates a new transaction (Transaction A) and makes Transaction A the ambient transaction. 그런 다음 Scope1은 각각 다른 TransactionScopeOption 값을 사용하여 세 개의 개체를 추가로 만듭니다.Scope1 then creates three more objects, each with a different TransactionScopeOption value. 예를 들어 scope2Required를 사용하여 만들어지고 앰비언트 트랜잭션이 있으므로 scope1에서 만든 첫 번째 트랜잭션에 참여합니다.For example, scope2 is created with Required, and since there is an ambient transaction, it joins the first transaction created by scope1. scope3은 새 트랜잭션의 루트 범위이고 scope4에는 앰비언트 트랜잭션이 없습니다.Note that scope3 is the root scope of a new transaction, and that scope4 has no ambient transaction.

TransactionScopeOption의 기본값이며 가장 일반적으로 사용되는 값은 Required이고 다른 값은 각각 고유한 용도를 가집니다.Although the default and most commonly used value of TransactionScopeOption is Required, each of the other values has its unique purpose.

트랜잭션 범위 내의 비트랜잭션 코드Non-transactional code inside a transaction scope

Suppress는 코드 섹션에서 수행 하는 작업을 유지 하려는 경우에 유용 하며, 작업이 실패 하는 경우 앰비언트 트랜잭션을 중단 하지 않으려는 경우에 유용 합니다.Suppress is useful when you want to preserve the operations performed by the code section, and do not want to abort the ambient transaction if the operations fail. 예를 들어 로깅 또는 감사 작업을 수행하려는 경우 또는 앰비언트 트랜잭션이 커밋 또는 중단되든 관계없이 구독자에게 이벤트를 게시하려는 경우에 유용합니다.For example, when you want to perform logging or audit operations, or when you want to publish events to subscribers regardless of whether your ambient transaction commits or aborts. 이 값을 사용하면 다음 예제와 같이 트랜잭션 범위 내부에 비트랜잭션 코드 섹션이 있을 수 있습니다.This value allows you to have a non-transactional code section inside a transaction scope, as shown in the following example.

using(TransactionScope scope1 = new TransactionScope())
{
    try
    {
        //Start of non-transactional section
        using(TransactionScope scope2 = new
            TransactionScope(TransactionScopeOption.Suppress))  
        {  
            //Do non-transactional work here  
        }  
        //Restores ambient transaction here
   }
   catch {}  
   //Rest of scope1
}

중첩된 범위 내부의 응답Voting inside a nested scope

중첩된 범위는 루트 범위의 앰비언트 트랜잭션에 참여할 수 있지만 중첩된 범위에서 Complete를 호출하면 루트 범위에 영향을 주지 않습니다.Although a nested scope can join the ambient transaction of the root scope, calling Complete in the nested scope has no affect on the root scope. 루트 범위에서 마지막 중첩 범위까지의 모든 범위가 트랜잭션을 커밋하도록 응답하는 경우에만 트랜잭션이 커밋됩니다.Only if all the scopes from the root scope down to the last nested scope vote to commit the transaction, will the transaction be committed. 중첩된 범위에서 Complete를 호출하지 않으면 앰비언트 트랜잭션이 즉시 중단되므로 루트 범위에 영향을 미칩니다.Not calling Complete in a nested scope will affect the root scope as the ambient transaction will immediately be aborted.

TransactionScope 시간 제한 설정Setting the TransactionScope timeout

TransactionScope의 오버로드된 생성자 중 일부는 트랜잭션의 시간 제한을 제어하는 데 사용되는 TimeSpan 형식의 값을 받아들입니다.Some of the overloaded constructors of TransactionScope accept a value of type TimeSpan, which is used to control the timeout of the transaction. 시간 제한을 0으로 설정하면 시간 제한이 없음을 의미합니다.A timeout set to zero means an infinite timeout. 무한 시간 제한은 대체로 코드를 단계별로 실행하여 비즈니스 논리의 문제를 격리하고 문제를 찾는 동안 디버그가 시간 초과되지 않도록 하려는 경우 디버깅에 유용합니다.Infinite timeout is useful mostly for debugging, when you want to isolate a problem in your business logic by stepping through your code, and you do not want the transaction you debug to time out while you attempt to locate the problem. 무한 시간 제한 값은 트랜잭션 교착 상태에 대한 안전 장치를 재정의하므로 다른 모든 경우에서는 사용 시 주의해야 합니다.Be extremely careful using the infinite timeout value in all other cases, because it overrides the safeguards against transaction deadlocks.

일반적으로 두 가지 경우에서 TransactionScope 시간 제한을 기본값이 아닌 값으로 설정합니다.You typically set the TransactionScope timeout to values other than default in two cases. 첫 번째는 개발 중으로, 애플리케이션이 중단된 트랜잭션을 처리하는 방법을 테스트하려는 경우입니다.The first is during development, when you want to test the way your application handles aborted transactions. 시간 제한을 더 작은 값(예: 1밀리초)으로 설정하여 트랜잭션이 실패하게 하고 오류 처리 코드를 확인할 수 있습니다.By setting the timeout to a small value (such as one millisecond), you cause your transaction to fail and can thus observe your error handling code. 이 값을 기본 시간 제한보다 작은 값으로 설정하는 두 번째 경우는 범위가 리소스 충돌과 관련되어 교착 상태가 발생한다고 생각하는 경우입니다.The second case in which you set the value to be less than the default timeout is when you believe that the scope is involved in resource contention, resulting in deadlocks. 이 경우 가능한 한 빨리 트랜잭션을 중단하고 기본 시간 제한이 만료될 때까지 기다리지 않으려고 합니다.In that case, you want to abort the transaction as soon as possible and not wait for the default timeout to expire.

범위가 앰비언트 트랜잭션에 참여하지만 앰비언트 트랜잭션이 설정된 시간 제한보다 작은 시간 제한을 지정하는 경우 TransactionScope 개체에 더 짧은 새 시간 제한이 적용되고 범위가 지정된 중첩 시간 내에 종료되어야 합니다. 그렇지 않으면 트랜잭션이 자동으로 중단됩니다.When a scope joins an ambient transaction but specifies a smaller timeout than the one the ambient transaction is set to, the new, shorter timeout is enforced on the TransactionScope object, and the scope must end within the nested time specified, or the transaction is automatically aborted. 중첩된 범위의 시간 제한이 앰비언트 트랜잭션의 시간 제한보다 크면 영향을 주지 않습니다.If the nested scope's timeout is more than that of the ambient transaction, it has no effect.

TransactionScope 격리 수준 설정Setting the TransactionScope isolation level

TransactionScope의 오버로드된 생성자 중 일부는 TransactionOptions 형식의 구조를 받아들여 시간 제한 값 외에 격리 수준을 지정합니다.Some of the overloaded constructors of TransactionScope accept a structure of type TransactionOptions to specify an isolation level, in addition to a timeout value. 기본적으로 트랜잭션은 격리 수준을 Serializable로 설정하여 실행됩니다.By default, the transaction executes with isolation level set to Serializable. Serializable이 아닌 격리 수준 선택은 일반적으로 읽기를 주로 사용하는 시스템에 사용됩니다.Selecting an isolation level other than Serializable is commonly used for read-intensive systems. 이 경우 트랜잭션 처리 이론과 트랜잭션 자체의 의미 체계, 관련된 동시성 문제, 시스템 일관성에 대한 영향을 이해해야 합니다.This requires a solid understanding of transaction processing theory and the semantics of the transaction itself, the concurrency issues involved, and the consequences for system consistency.

또한 모든 리소스 관리자가 모든 격리 수준을 지원하지는 않으며, 구성된 수준보다 더 높은 수준의 트랜잭션에 참여하도록 선택할 수 있습니다.In addition, not all resource managers support all levels of isolation, and they may elect to take part in the transaction at a higher level than the one configured.

Serializable 외의 모든 격리 수준에서 동일한 정보에 액세스하는 다른 트랜잭션으로 인한 불일치가 발생할 수 있습니다.Every isolation level besides Serializable is susceptible to inconsistency resulting from other transactions accessing the same information. 각 격리 수준의 차이점은 읽기 및 쓰기 잠금의 사용 방식입니다.The difference between the different isolation levels is in the way read and write locks are used. 트랜잭션이 리소스 관리자의 데이터에 액세스할 때만 잠금을 유지하거나 트랜잭션이 커밋 또는 중단될 때까지 유지할 수 있습니다.A lock can be held only when the transaction accesses the data in the resource manager, or it can be held until the transaction is committed or aborted. 전자는 처리량 향상에 효과적이고 후자는 일관성 유지에 효과적입니다.The former is better for throughput, the latter for consistency. 두 종류의 잠금과 두 종류의 작업(읽기/쓰기)으로 네 가지 기본 격리 수준이 만들어집니다.The two kinds of locks and the two kinds of operations (read/write) give four basic isolation levels. 자세한 내용은 IsolationLevel를 참조하세요.See IsolationLevel for more information.

중첩된 TransactionScope 개체를 사용하는 경우 모든 중첩 범위가 앰비언트 트랜잭션에 참여하려면 동일한 격리 수준을 사용하도록 구성해야 합니다.When using nested TransactionScope objects, all nested scopes must be configured to use exactly the same isolation level if they want to join the ambient transaction. 중첩된 TransactionScope 개체가 앰비언트 트랜잭션에 참여하려고 하지만 다른 격리 수준을 지정하는 경우 ArgumentException이 throw됩니다.If a nested TransactionScope object tries to join the ambient transaction yet it specifies a different isolation level, an ArgumentException is thrown.

COM+와의 상호 운용성Interop with COM+

TransactionScope 인스턴스를 만드는 경우 생성자 중 하나에 EnterpriseServicesInteropOption 열거를 사용하여 COM+와 상호 작용하는 방법을 지정할 수 있습니다.When you create a new TransactionScope instance, you can use the EnterpriseServicesInteropOption enumeration in one of the constructors to specify how to interact with COM+. 이에 대 한 자세한 내용은 엔터프라이즈 서비스 및 COM + 트랜잭션과의 상호 운용성을 참조 하세요.For more information on this, see Interoperability with Enterprise Services and COM+ Transactions.

참조See also