Aracılığıyla paylaş


SQL Server ile System.Transactions tümleştirmesi

.NET Framework sürüm 2.0, ad alanı üzerinden System.Transactions erişilebilen bir işlem çerçevesi kullanıma sunulmuştur. Bu çerçeve, işlemleri ADO.NET dahil olmak üzere .NET Framework ile tamamen tümleştirilmiş bir şekilde kullanıma sunar.

Programlama geliştirmelerine ek olarak ve System.Transactions ADO.NET, işlemlerle çalışırken iyileştirmeleri koordine etmek için birlikte çalışabilir. Yükseltilebilir işlem, gerektiğinde otomatik olarak tam dağıtılmış bir işleme yükseltilebilen basit (yerel) bir işlemdir.

ADO.NET 2.0'dan başlayarak, System.Data.SqlClient SQL Server ile çalışırken tanıtılabilir işlemleri destekler. Yükseltilebilir bir işlem, eklenen ek yük gerekmediği sürece dağıtılmış bir işlemin ek yükünü çağırmaz. Tanıtılabilir işlemler otomatiktir ve geliştiricinin müdahalesi gerekmez.

Tanıtılabilir işlemler yalnızca SQL Server (SqlClient) için .NET Framework Veri Sağlayıcısı SQL Server ile kullandığınızda kullanılabilir.

Tanıtılabilir İşlemler Oluşturma

SQL Server için .NET Framework Sağlayıcısı, .NET Framework System.Transactions ad alanında sınıflar aracılığıyla işlenen yükseltilebilir işlemler için destek sağlar. Yükseltilebilir işlemler, gerekli olana kadar dağıtılmış işlem oluşturmayı erteleyerek dağıtılmış işlemleri iyileştirir. Yalnızca bir kaynak yöneticisi gerekiyorsa, dağıtılmış işlem gerçekleşmez.

Not

Kısmen güvenilen bir senaryoda, DistributedTransactionPermission bir işlem dağıtılmış bir işleme yükseltildiğinde gereklidir.

Tanıtılabilir İşlem Senaryoları

Dağıtılmış işlemler genellikle işlemde erişilen tüm kaynak yöneticilerini tümleştiren Microsoft Dağıtılmış İşlem Düzenleyicisi (MS DTC) tarafından yönetilen önemli sistem kaynaklarını kullanır. Tanıtılabilir işlem, işi basit bir SQL Server işlemine etkili bir System.Transactions şekilde devreden özel bir işlem biçimidir. System.Transactions, System.Data.SqlClientve SQL Server, işlemin işlenmesinde yer alan çalışmayı koordine eder ve gerektiğinde tam dağıtılmış bir işleme yükselter.

Yükseltilebilir işlemleri kullanmanın avantajı, etkin TransactionScope bir işlem kullanılarak bir bağlantı açıldığında ve başka hiçbir bağlantı açılmadığında, işlemin tam dağıtılmış bir işlemin ek yükünü doğurma yerine basit bir işlem olarak işlemesidir.

Bağlantı Dizesi Anahtar Sözcükleri

ConnectionString özelliği, Enlistişlem bağlamlarını algılayıp algılamayacağını ve bağlantıyı dağıtılmış bir işlemde otomatik olarak listeleyip System.Data.SqlClient listelemeyeceğini belirten bir anahtar sözcüğünü destekler. ise Enlist=true, bağlantı, açılış iş parçacığının geçerli işlem bağlamında otomatik olarak listeye eklenir. SqlClient iseEnlist=false, bağlantı dağıtılmış bir işlemle etkileşim kurmaz. için Enlist varsayılan değer true değeridir. bağlantı dizesi belirtilmezseEnlist, bağlantı açıldığında algılanırsa bağlantı otomatik olarak dağıtılmış bir işleme eklenir.

Transaction Binding bir bağlantı dizesi içindeki SqlConnection anahtar sözcükler, bağlantının listelenmiş System.Transactions bir işlemle ilişkisini denetler. Ayrıca özelliği aracılığıyla TransactionBinding SqlConnectionStringBuilderda kullanılabilir.

Aşağıdaki tabloda olası değerler açıklanmaktadır.

Anahtar sözcük Açıklama
Örtük Bağlamayı Kaldırma Varsayılan. Bağlantı sona erdiğinde işlemden ayrılır ve otomatik komut moduna geri döner.
Açık Bağlamayı Kaldır İşlem kapatılana kadar bağlantı işleme bağlı kalır. İlişkili işlem etkin değilse veya ile eşleşmiyorsa Currentbağlantı başarısız olur.

TransactionScope Kullanma

sınıfı, TransactionScope dağıtılmış bir işlemdeki bağlantıları örtük olarak listeleyerek bir kod bloğunu işlemsel hale getirir. Bloktan çıkmadan önce bloğun TransactionScope sonunda yöntemini çağırmanız Complete gerekir. Bloktan çıkmak yöntemini çağırır Dispose . Kodun kapsamdan ayrılmasına neden olan bir özel durum oluşturulduysa, işlem durduruldu olarak kabul edilir.

Kullanma bloğundan çıkıldığında nesnede TransactionScope çağrıldığından Dispose emin olmak için bir using blok kullanmanızı öneririz. bekleyen işlemlerin yürütülememesi veya geri alınamaması, için varsayılan zaman aşımının bir dakika olması nedeniyle performansa TransactionScope önemli ölçüde zarar verebilir. Deyimini using kullanmazsanız, tüm işleri bir Try blok içinde gerçekleştirmeniz ve açıkça bloğunda Dispose Finally yöntemini çağırmanız gerekir.

içinde TransactionScopebir özel durum oluşursa, işlem tutarsız olarak işaretlenir ve terk edilir. atıldığında TransactionScope geri alınır. Özel durum oluşmazsa, katılan işlemler işleme alır.

Not

sınıfı, TransactionScope varsayılan olarak ile bir IsolationLevel Serializable işlem oluşturur. Uygulamanıza bağlı olarak, uygulamanızda yüksek çekişmelerden kaçınmak için yalıtım düzeyini düşürmeyi düşünebilirsiniz.

Not

Önemli veritabanı kaynaklarını kullandıklarından, dağıtılmış işlemler içinde yalnızca güncelleştirmeleri, eklemeleri ve silmeleri gerçekleştirmenizi öneririz. Select deyimleri veritabanı kaynaklarını gereksiz yere kilitler ve bazı senaryolarda, seçim işlemleri için işlem kullanmanız gerekebilir. Diğer işlem yapılmış kaynak yöneticilerini içermediği sürece, veritabanı dışı tüm çalışmalar işlem kapsamı dışında yapılmalıdır. İşlem kapsamındaki bir özel durum işlemin işlenmesini engellese de, sınıfın TransactionScope kodunuzun işlem kapsamı dışında yaptığı değişiklikleri geri alma için bir sağlama yoktur. İşlem geri alınırken bazı eylemler gerçekleştirmeniz gerekiyorsa, kendi arabirimi uygulamanızı IEnlistmentNotification yazmanız ve işlemde açıkça listelemeniz gerekir.

Örnek

ile System.Transactions çalışmak için System.Transactions.dll bir başvurunuz olması gerekir.

Aşağıdaki işlev, bir blokta TransactionScope sarmalanmış iki farklı nesneyle temsil edilen iki SqlConnection farklı SQL Server örneğinde yükseltilebilir bir işlemin nasıl oluşturulacağını gösterir. Kod bloğunu bir using deyimiyle oluşturur TransactionScope ve içinde otomatik olarak listeleyen TransactionScopeilk bağlantıyı açar. İşlem başlangıçta tam dağıtılmış bir işlem olarak değil basit bir işlem olarak listelenmiştir. İkinci bağlantı yalnızca ilk bağlantıdaki TransactionScope komut bir özel durum oluşturmazsa içinde listelenir. İkinci bağlantı açıldığında, işlem otomatik olarak tam dağıtılmış bir işleme yükseltilir. Complete yöntemi çağrılır ve bu yöntem yalnızca hiçbir özel durum atlanmamışsa işlemi işler. Bloğun herhangi bir noktasında TransactionScope bir özel durum oluşturulduysa çağrılmaz Complete ve dağıtılan işlem bloğunun using sonunda atıldığında TransactionScope geri alınır.

// This function takes arguments for the 2 connection strings and commands in order
// to create a transaction involving two SQL Servers. It returns a value > 0 if the
// transaction committed, 0 if the transaction 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 RDBMS such as Oracle 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();

    // Create the TransactionScope in which to execute the commands, guaranteeing
    // that both commands will commit or roll back as a single unit of work.
    using (TransactionScope scope = new TransactionScope())
    {
        using (SqlConnection connection1 = new SqlConnection(connectString1))
        {
            try
            {
                // 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 by opening connection2
                // only when there is a chance that the transaction can commit.
                using (SqlConnection connection2 = new SqlConnection(connectString2))
                    try
                    {
                        // The transaction is promoted 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);
                    }
                    catch (Exception ex)
                    {
                        // Display information that command2 failed.
                        writer.WriteLine("returnValue for command2: {0}", returnValue);
                        writer.WriteLine("Exception Message2: {0}", ex.Message);
                    }
            }
            catch (Exception ex)
            {
                // Display information that command1 failed.
                writer.WriteLine("returnValue for command1: {0}", returnValue);
                writer.WriteLine("Exception Message1: {0}", ex.Message);
            }
        }

        // If an exception has been thrown, Complete will not
        // be called and the transaction is rolled back.
        scope.Complete();
    }

    // The returnValue is greater than 0 if the transaction committed.
    if (returnValue > 0)
    {
        writer.WriteLine("Transaction was committed.");
    }
    else
    {
        // You could write additional business logic here, notify the caller by
        // throwing a TransactionAbortedException, or log the failure.
        writer.WriteLine("Transaction rolled back.");
    }

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

    return returnValue;
}
' This function takes arguments for the 2 connection strings and commands in order
' to create a transaction involving two SQL Servers. It returns a value > 0 if the
' transaction committed, 0 if the transaction 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 RDBMS such as Oracle 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

    ' Create the TransactionScope in which to execute the commands, guaranteeing
    ' that both commands will commit or roll back as a single unit of work.
    Using scope As New TransactionScope()
        Using connection1 As New SqlConnection(connectString1)
            Try
                ' 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 by opening connection2
                ' only when there is a chance that the transaction can commit.
                Using connection2 As New SqlConnection(connectString2)
                    Try
                        ' The transaction is promoted 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)

                    Catch ex As Exception
                        ' Display information that command2 failed.
                        writer.WriteLine("returnValue for command2: {0}", returnValue)
                        writer.WriteLine("Exception Message2: {0}", ex.Message)
                    End Try
                End Using

            Catch ex As Exception
                ' Display information that command1 failed.
                writer.WriteLine("returnValue for command1: {0}", returnValue)
                writer.WriteLine("Exception Message1: {0}", ex.Message)
            End Try
        End Using

        ' If an exception has been thrown, Complete will
        ' not be called and the transaction is rolled back.
        scope.Complete()
    End Using

    ' The returnValue is greater than 0 if the transaction committed.
    If returnValue > 0 Then
        writer.WriteLine("Transaction was committed.")
    Else
        ' You could write additional business logic here, notify the caller by
        ' throwing a TransactionAbortedException, or log the failure.
       writer.WriteLine("Transaction rolled back.")
     End If

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

    Return returnValue
End Function

Ayrıca bkz.