Megosztás a következőn keresztül:


System.Transactions integráció az SQL Serverrel

A .NET-keretrendszer 2.0-s verziója bevezetett egy tranzakciós keretrendszert, amely a System.Transactions névtéren keresztül érhető el. Ez a keretrendszer olyan módon teszi elérhetővé a tranzakciókat, hogy teljes mértékben integrálva legyen a .NET-keretrendszer, beleértve a ADO.NET.

A programozhatósági fejlesztések System.Transactions mellett a ADO.NET együttműködve koordinálhatja az optimalizálást a tranzakciók használatakor. A promóciós tranzakció egy egyszerű (helyi) tranzakció, amely automatikusan előléptethető egy teljesen elosztott tranzakcióra igény szerint.

A ADO.NET 2.0-tól kezdve támogatja a System.Data.SqlClient promóciós tranzakciókat az SQL Server használatakor. A promóciós tranzakció csak akkor hívja meg az elosztott tranzakciók többletterhelését, ha a többletterhelésre szükség van. A promóciós tranzakciók automatikusak, és nem igényelnek beavatkozást a fejlesztőtől.

A promóciós tranzakciók csak akkor érhetők el, ha a .NET-keretrendszer SQL Server-adatszolgáltatót (SqlClient) használja az SQL Serverrel.

Promóciós tábla tranzakcióinak létrehozása

Az SQL Server .NET-keretrendszer-szolgáltatója támogatja a promóciós tranzakciókat, amelyeket a .NET-keretrendszer System.Transactions névtér osztályai kezelnek. A promóciós tranzakciók optimalizálják az elosztott tranzakciókat úgy, hogy elhalasztják az elosztott tranzakciók létrehozását, amíg szükség nem lesz rá. Ha csak egy erőforrás-kezelőre van szükség, nem történik elosztott tranzakció.

Feljegyzés

Részlegesen megbízható forgatókönyv esetén a DistributedTransactionPermission szükséges, ha egy tranzakciót előléptetnek egy elosztott tranzakcióban.

Promóciós tranzakciós forgatókönyvek

Az elosztott tranzakciók általában jelentős rendszererőforrásokat használnak fel, amelyeket a Microsoft Elosztott tranzakció koordinátora (MS DTC) felügyel, amely integrálja a tranzakcióban elért összes erőforrás-kezelőt. A promóciós tranzakció egy tranzakció speciális formája System.Transactions , amely hatékonyan delegálja a munkát egy egyszerű SQL Server-tranzakcióba. System.Transactions, System.Data.SqlClientés az SQL Server koordinálja a tranzakció kezelésével kapcsolatos munkát, és szükség szerint egy teljes elosztott tranzakcióra előlépteti.

A promóciós tranzakciók használatának előnye, hogy ha egy kapcsolat aktív TransactionScope tranzakcióval nyílik meg, és nem nyílik meg más kapcsolat, a tranzakció egyszerű tranzakcióként véglegesít, ahelyett, hogy a teljes elosztott tranzakció többletterhelésével jár.

Csatlakozás ion sztringszavai

A ConnectionString tulajdonság egy kulcsszót támogat, amely jelzi, Enlisthogy észleli-e System.Data.SqlClient a tranzakciós környezeteket, és automatikusan bevonja a kapcsolatot egy elosztott tranzakcióba. Ha Enlist=true, a kapcsolat automatikusan megjelenik a nyitó szál aktuális tranzakciós környezetében. Ha Enlist=falsea SqlClient kapcsolat nem működik együtt elosztott tranzakcióval. Az alapértelmezett érték Enlist igaz. Ha Enlist nincs megadva a kapcsolati sztring, a rendszer automatikusan felvesz egy elosztott tranzakcióba, ha a kapcsolat megnyitásakor észlel egy kapcsolatot.

A Transaction Binding kapcsolati sztring kulcsszavai SqlConnection szabályozzák a kapcsolat társítását egy bevont System.Transactions tranzakcióval. A tulajdonságon keresztül TransactionBindingSqlConnectionStringBuilderis elérhető.

Az alábbi táblázat a lehetséges értékeket ismerteti.

Kulcsszó Leírás
Implicit kötés feloldva Az alapértelmezett érték. A kapcsolat megszűnik a tranzakciótól, és visszaáll az automatikus kapcsolódási módra.
Explicit kötés megszüntetése A kapcsolat a tranzakcióhoz marad csatolva, amíg a tranzakció be nem záródik. A kapcsolat sikertelen lesz, ha a társított tranzakció nem aktív vagy nem egyezik Current.

A TransactionScope használata

Az TransactionScope osztály egy kódblokkot tranzakcióssá tesz úgy, hogy implicit módon bevonja a kapcsolatokat egy elosztott tranzakcióba. Mielőtt elhagyná, Complete meg kell hívnia a metódust a TransactionScope blokk végén. A blokk elhagyása meghívja a metódust Dispose . Ha olyan kivétel történt, amely miatt a kód elhagyja a hatókört, a tranzakció megszakítottnak minősül.

Javasoljuk, hogy használjon egy blokkot using annak érdekében, hogy Dispose a blokk kilépésekor a rendszer meghívja TransactionScope az objektumot. A függőben lévő tranzakciók véglegesítésének vagy visszaállításának elmulasztása jelentősen károsíthatja a teljesítményt, mert az alapértelmezett időtúllépés egy TransactionScope perc. Ha nem használ utasítást using , minden munkát el kell végeznie egy Try blokkban, és explicit módon meg kell hívnia a Dispose blokk metódusát Finally .

Ha kivétel történik a TransactionScopetranzakcióban, a tranzakció inkonzisztensként van megjelölve, és a rendszer megszakítja. A rendszer a megsemmisítéskor TransactionScope vissza fogja dobni. Ha nem történik kivétel, a részt vevő tranzakciók véglegesítésre kerülnek.

Feljegyzés

Az TransactionScope osztály alapértelmezés szerint létrehoz egy tranzakciót SerializableIsolationLevel. Az alkalmazástól függően érdemes lehet csökkenteni az elkülönítési szintet, hogy elkerülje a magas versengést az alkalmazásban.

Feljegyzés

Javasoljuk, hogy csak a frissítéseket, beszúrásokat és törléseket végezze el az elosztott tranzakciókon belül, mert jelentős adatbázis-erőforrásokat használnak fel. A kiválasztási utasítások szükségtelenül zárolhatják az adatbázis erőforrásait, és bizonyos esetekben előfordulhat, hogy tranzakciókat kell használnia a kiválasztásokhoz. Az adatbázison kívüli munkákat a tranzakció hatókörén kívül kell elvégezni, kivéve, ha más átjátszott erőforrás-kezelőket is érint. Bár a tranzakció hatókörének kivétele megakadályozza a tranzakció véglegesítését, az TransactionScope osztály nem rendelkezik a kód azon módosításainak visszaállítására, amelyek a tranzakció hatókörén kívül történtek. Ha a tranzakció visszagördülésekor valamilyen műveletet kell végrehajtania, meg kell írnia a IEnlistmentNotification felület saját implementációját, és explicit módon be kell jelentkeznie a tranzakcióba.

Példa

A használata System.Transactions megköveteli, hogy hivatkozzon System.Transactions.dll.

Az alábbi függvény bemutatja, hogyan hozhat létre promóciós tranzakciót két különböző SQL Server-példányon, amelyeket két különböző SqlConnection objektum jelöl, amelyek egy TransactionScope blokkba vannak csomagolva. A kód egy using utasítással hozza létre a TransactionScope blokkot, és megnyitja az első kapcsolatot, amely automatikusan a TransactionScope. A tranzakció kezdetben egyszerű tranzakcióként van felvéve, nem pedig teljes elosztott tranzakcióként. A második kapcsolat csak akkor szerepel a TransactionScope listán, ha az első kapcsolat parancsa nem ad kivételt. A második kapcsolat megnyitásakor a rendszer automatikusan előlépteti a tranzakciót egy teljes elosztott tranzakcióra. A Complete rendszer meghívja a metódust, amely csak akkor véglegesíti a tranzakciót, ha nem történt kivétel. Ha a blokk bármely pontján kivétel történt, Complete a TransactionScope rendszer nem hívja meg, és az elosztott tranzakció visszagördül, amikor a TransactionScope blokk végén using el van adva.

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

Lásd még