İşlem Kapsamı Kullanarak Örtük İşlem Uygulama

sınıfı, TransactionScope işlemle etkileşim kurmanıza gerek kalmadan bir kod bloğunu bir işleme katılan olarak işaretlemek için basit bir yol sağlar. İşlem kapsamı ortam işlemini otomatik olarak seçebilir ve yönetebilir. Kullanım kolaylığı ve verimliliği nedeniyle, bir işlem uygulaması geliştirirken sınıfını TransactionScope kullanmanız önerilir.

Ayrıca, kaynakları işlemle açıkça listelemeniz gerekmez. Herhangi bir System.Transactions kaynak yöneticisi (SQL Server 2005 gibi), kapsam tarafından oluşturulan ve otomatik olarak listeye alınan bir ortam işleminin varlığını algılayabilir.

İşlem kapsamı oluşturma

Aşağıdaki örnek, bir basit kullanımını gösterir TransactionScope sınıfı.

// 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

İşlem kapsamı, yeni TransactionScope bir nesne oluşturduğunuzda başlatılır. Kod örneğinde gösterildiği gibi, kapsamları bir using deyimiyle oluşturmanız önerilir. deyimi using hem C# hem de Visual Basic'te kullanılabilir ve kapsamın düzgün bir şekilde atıldığından emin olmak için . try..finally bloğu gibi çalışır.

örneği TransactionScopeoluşturduğunuzda, hangi işleme katılılacağı işlem yöneticisi tarafından belirlenir. Kapsam belirlendikten sonra her zaman bu işleme katılır. Karar iki faktöre dayanır: ortam işleminin mevcut olup olmadığı ve oluşturucudaki parametrenin TransactionScopeOption değeri. Ortam işlemi, kodunuzun yürütüldiği işlemdir. Sınıfın statik Transaction.Current özelliğini Transaction çağırarak ortam işlemine başvuru alabilirsiniz. Bu parametrenin nasıl kullanıldığı hakkında daha fazla bilgi için bu konunun TransactionScopeOption kullanarak işlem akışını yönetme bölümüne bakın.

İşlem kapsamını tamamlama

Uygulamanız bir işlemde gerçekleştirmek istediği tüm işi tamamladığında, işlem yöneticisine işlemin işlenmesinin TransactionScope.Complete kabul edilebilir olduğunu bildirmek için yöntemini yalnızca bir kez çağırmanız gerekir. çağrısının Complete bloğundaki son deyim using olarak kullanılması çok iyi bir uygulamadır.

İşlem yöneticisi bunu bir sistem hatası olarak veya işlem kapsamında oluşan bir özel duruma eşdeğer olarak yorumladığı için bu yöntemin çağrılamaması işlemi durdurur. Ancak, bu yöntemin çağrılması işlemin gerçekleştirildiğini garanti etmez. Bu yalnızca durumunuzu işlem yöneticisine bildirmenin bir yoludur. yöntemini çağırdıktan Complete sonra artık özelliğini kullanarak ortam işlemine Current erişemezsiniz ve bunu yapmaya çalıştığınızda bir özel durum oluşturulur.

TransactionScope Nesne başlangıçta işlemi oluşturduysa, işlem yöneticisi tarafından işlemin gerçek olarak işlenmesi, bloktaki son kod satırından using sonra gerçekleşir. İşlemi oluşturmadıysa, nesnenin sahibi CommittableTransaction tarafından her Commit çağrıldığında işleme gerçekleşir. Bu noktada işlem yöneticisi kaynak yöneticilerini çağırır ve yöntemin nesne üzerinde TransactionScope çağrılıp çağrılmadığına Complete bağlı olarak onları işleme veya geri alma konusunda bilgilendirır.

deyimi, using bir özel durum oluştuğunda Dispose bile nesnesinin TransactionScope yönteminin çağrılmasını sağlar. yöntemi, Dispose işlem kapsamının sonunu işaretler. Bu yöntem çağrıldıktan sonra oluşan özel durumlar işlemi etkilemeyebilir. Bu yöntem ayrıca ortam işlemini önceki durumuna geri yükler.

TransactionAbortedException Kapsam işlemi oluşturursa ve işlem durdurulduysa bir oluşturulur. İşlem TransactionInDoubtException yöneticisi bir İşleme kararına ulaşamazsa bir oluşturulur. İşlem işlenirse hiçbir özel durum oluşturulur.

bir işlemi geri döndürme

Bir işlemi geri almak istiyorsanız, işlem kapsamında yöntemini çağırmamalısınız Complete . Örneğin, kapsam içinde bir özel durum. Katıldığı işlem geri alınır.

TransactionScopeOption kullanarak işlem akışını yönetme

İşlem kapsamı, aşağıdaki örnekteki yönteminde TransactionScope olduğu gibi RootMethod kendi kapsamını kullanan bir yöntemin içinden kullanan bir yöntem çağrılarak iç içe yerleştirilebilir.

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

En üstteki işlem kapsamı kök kapsam olarak adlandırılır.

sınıfı, TransactionScope kapsamın işlem davranışını tanımlayan türünün TransactionScopeOptionbir numaralandırmasını kabul eden birkaç aşırı yüklenmiş oluşturucu sağlar.

Bir TransactionScope nesnenin üç seçenek vardır:

  • Ortam işlemine katılın veya yoksa yeni bir işlem oluşturun.

  • Yeni bir kök kapsam oluşturun, yani yeni bir işlem başlatın ve bu işlemin kendi kapsamındaki yeni ortam işlemi olmasını sağlayın.

  • Bir işleme hiç katılmayın. Sonuç olarak ortam işlemi yoktur.

Kapsam ile Requiredörneği oluşturulursa ve bir ortam işlemi varsa, kapsam bu işlemi birleştirir. Öte yandan ortam işlemi yoksa kapsam yeni bir işlem oluşturur ve kök kapsam olur. Bu varsayılan değerdir. Kullanıldığında Required , kapsam içindeki kodun kök veya yalnızca ortam işlemine katılması fark etmez. Her iki durumda da aynı şekilde çalışması.

Kapsamı ile örneği varsa RequiresNew, her zaman bir kök kapsam olur. Yeni bir işlem başlatır ve bu işlemin kapsamın içindeki yeni ortam işlemi olur.

Kapsamın örneği ile Suppressoluşturulursa, ortam işleminin mevcut olup olmadığına bakılmaksızın hiçbir zaman işlemde yer almaz. Bu değerle örnek bir kapsamın her zaman null ortam işlemi vardır.

Yukarıdaki seçenekleri aşağıdaki tabloda özetlenmiştir.

TransactionScopeOption Ortam İşlemi Kapsam bölümü alır
Gerekli Hayır Yeni İşlem (kök olacaktır)
Yeni gerektirir Hayır Yeni İşlem (kök olacaktır)
Önle Hayır İşlem Yok
Zorunlu Yes Ortam İşlemi
Yeni gerektirir Yes Yeni İşlem (kök olacaktır)
Önle Yes İşlem Yok

Bir TransactionScope nesne mevcut bir ortam işlemine katıldığında kapsam nesnesinin atılması, kapsam işlemi durdurmadığı sürece işlemi sonlandıramayabilir. Ortam işlemi bir kök kapsam tarafından oluşturulduysa, yalnızca kök kapsam atıldığında işlemde çağrılır Commit . İşlem el ile oluşturulduysa, işlem durdurulduğunda veya oluşturucusu tarafından işlendiğinde sona erer.

Aşağıdaki örnekte gösterildiği bir TransactionScope üç iç içe kapsamlı nesneler, farklı bir her örneklenen oluşturan nesne TransactionScopeOption değeri.

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))
    {
        //...  
    }
}

Örnekte, ile yeni bir kapsam (scope1) oluşturan herhangi bir ortam işlemi olmayan bir kod bloğu gösterilmektedir Required. Kapsam scope1 , yeni bir işlem (İşlem A) oluşturduğundan ve İşlem A'nın ortam işlemi olmasını sağladığından bir kök kapsamdır. Scope1Daha sonra her farklı bir ile üç daha fazla nesne oluşturur TransactionScopeOption değeri. Örneğin, scope2 ile Requiredoluşturulur ve bir ortam işlemi olduğundan tarafından scope1oluşturulan ilk işlemi birleştirir. scope3 Yeni bir işlemin kök kapsamı olduğunu ve scope4 ortam işlemi olmadığını unutmayın.

Değerini varsayılan ve en sık kullanılan olsa da TransactionScopeOption olan Required, her diğer değerlerinin benzersiz amacı vardır.

İşlem kapsamı içinde işlem dışı kod

Suppress kod bölümü tarafından gerçekleştirilen işlemleri korumak istediğinizde ve işlemler başarısız olursa ortam işlemini durdurmak istemediğinizde yararlıdır. Örneğin, günlük veya denetim işlemleri gerçekleştirmek istediğinizde veya ortam işleminizin işleme veya durdurma işlemlerinden bağımsız olarak olayları abonelere yayımlamak istediğinizde. Bu değer, aşağıdaki örnekte gösterildiği gibi işlem kapsamı içinde işlem dışı bir kod bölümüne sahip olmanıza olanak tanır.

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
}

İç içe bir kapsam içinde oylama

İç içe yerleştirilmiş bir kapsam kök kapsamın ortam işlemini birleştirese de, iç içe kapsamda çağrılması Complete kök kapsam üzerinde hiçbir etkiye sahip değildir. İşlem yalnızca kök kapsamdan iç içe geçen son kapsama kadar tüm kapsamlar işlemi işlemeye oy verirse işlenir. ortam işlemi hemen durdurulacağı için iç içe bir kapsamda çağrı Complete yapılmaması kök kapsamı etkiler.

TransactionScope zaman aşımını ayarlama

öğesinin aşırı yüklenmiş oluşturucularından TransactionScope bazıları, işlemin zaman aşımını denetlemek için kullanılan türündeki TimeSpanbir değeri kabul eder. Sıfır olarak ayarlanmış bir zaman aşımı sonsuz bir zaman aşımı anlamına gelir. Kodunuzda adım adım ilerleyerek iş mantığınızdaki bir sorunu yalıtmak istediğinizde ve sorunu bulmaya çalışırken hata ayıkladığınız işlemin zaman aşımına ulanmasını istemediğinizde, sonsuz zaman aşımı çoğunlukla hata ayıklama için yararlıdır. İşlem kilitlenmelerine karşı korumaları geçersiz kılacağından, diğer tüm durumlarda sonsuz zaman aşımı değerini kullanırken son derece dikkatli olun.

Genellikle ayarlanabilir TransactionScope zaman aşımına uğramak üzere iki durumda da varsayılan dışındaki değerler. İlki, uygulamanızın durdurulan işlemleri işleme biçimini test etmek istediğiniz geliştirme sırasındadır. Zaman aşımını küçük bir değere (bir milisaniye gibi) ayarlayarak işleminizin başarısız olmasına neden olursunuz ve bu nedenle hata işleme kodunuzu gözlemleyebilirsiniz. Kapsam içinde kaynak talebi, söz konusu kilitlenmeleri kaynaklanan düşünüyorsanız, varsayılan zaman aşımı değerinden bir değere ayarlamanız ikinci durumdur. Bu durumda, işlemi en kısa sürede durdurmak ve varsayılan zaman aşımının süresinin dolmasını beklememek istersiniz.

Kapsam bir ortam işlemini birleştirdiğinde ancak ortam işleminin ayarlandığı işlemden daha küçük bir zaman aşımı belirttiğinde, nesne üzerinde TransactionScope yeni, daha kısa zaman aşımı uygulanır ve kapsam belirtilen iç içe yerleştirilmiş süre içinde bitmelidir veya işlem otomatik olarak durdurulır. İç içe kapsamın zaman aşımı, ortam işleminin zaman aşımından daha fazlaysa, hiçbir etkisi olmaz.

TransactionScope yalıtım düzeyini ayarlama

öğesinin aşırı yüklenmiş oluşturucularından TransactionScope bazıları, bir zaman aşımı değerine ek olarak yalıtım düzeyi belirtmek için tür TransactionOptions yapısını kabul eder. Varsayılan olarak, işlem yalıtım düzeyi olarak ayarlanmış şekilde Serializableyürütülür. Başka bir yalıtım düzeyi seçme Serializable yaygın olarak okuma yoğun sistemleri için kullanılır. Bunun için işlem işleme teorisinin ve işlemin semantiğinin, ilgili eşzamanlılık sorunlarının ve sistem tutarlılığının sonuçlarının sağlam bir şekilde anlaşılması gerekir.

Buna ek olarak, tüm kaynak yöneticileri tüm yalıtım düzeylerini desteklemez ve yapılandırılandan daha yüksek bir düzeyde işlemde yer almayı seçebilir.

Ayrıca Serializable her yalıtım düzeyi, aynı bilgilere erişen diğer işlemlerden kaynaklanan tutarsızlığa açıktır. Farklı yalıtım düzeyleri arasındaki farkı biçiminde okunur ve yazma kilitler kullanılır. Kilit yalnızca işlem kaynak yöneticisindeki verilere eriştiğinde tutulabilir veya işlem tamamlanana veya durdurulana kadar tutulabilir. Eski verimlilik, tutarlılık ikincisi için iyidir. Kilit iki tür ve işlemleri (okuma/yazma) iki tür dört temel yalıtım düzeyi verin. Daha fazla bilgi edinmek için bkz. IsolationLevel.

İç içe TransactionScope nesneler kullanılırken, ortam işlemine katılmak isteyen tüm iç içe kapsamların tam olarak aynı yalıtım düzeyini kullanacak şekilde yapılandırılması gerekir. İç içe yerleştirilmiş TransactionScope bir nesne ortam işlemini birleştirmeye çalışırsa ancak farklı bir yalıtım düzeyi belirtirse, bir ArgumentException oluşturulur.

COM + ile birlikte çalışma

Yeni TransactionScope bir örnek oluşturduğunuzda, COM+ ile nasıl etkileşim kurulacağını belirtmek için oluşturuculardan birinde numaralandırmayı kullanabilirsiniz EnterpriseServicesInteropOption . Bu konuda daha fazla bilgi için bkz . Enterprise Services ve COM+ İşlemleri ile Birlikte Çalışabilirlik.

Ayrıca bkz.