Delen via


Een expliciete transactie implementeren met behulp van CommittableTransaction

De CommittableTransaction klasse biedt een expliciete manier voor toepassingen om een transactie te gebruiken, in plaats van impliciet de TransactionScope klasse te gebruiken. Het is handig voor toepassingen die dezelfde transactie willen gebruiken voor meerdere functie-aanroepen of meerdere thread-aanroepen. In tegenstelling tot de TransactionScope klasse moet de schrijver van de toepassing de Commit en Rollback methoden specifiek aanroepen om de transactie door te voeren of af te breken.

Overzicht van de klasse CommittableTransaction

De CommittableTransaction klasse is afgeleid van de Transaction klasse en biedt daarom alle functionaliteit van de laatste. Dit is met name handig voor de Rollback Transaction klasse die ook kan worden gebruikt om een CommittableTransaction object terug te draaien.

De Transaction klasse is vergelijkbaar met de CommittableTransaction klasse, maar biedt Commit geen methode. Hiermee kunt u het transactieobject (of klonen hiervan) doorgeven aan andere methoden (mogelijk op andere threads) terwijl u nog steeds controleert wanneer de transactie wordt doorgevoerd. De aangeroepen code kan de transactie inschakelen en stemmen, maar alleen de maker van het CommittableTransaction object heeft de mogelijkheid om de transactie door te voeren.

Let op het volgende bij het werken met de CommittableTransaction klasse.

  • Bij het maken van een CommittableTransaction transactie wordt de omgevingstransactie niet ingesteld. U moet de omgevingstransactie specifiek instellen en opnieuw instellen om ervoor te zorgen dat resourcemanagers, indien van toepassing, onder de juiste transactiecontext werken. De manier om de huidige omgevingstransactie in te stellen, is door de statische Current eigenschap op het globale Transaction object in te stellen.

  • Een CommittableTransaction object kan niet opnieuw worden gebruikt. Zodra een CommittableTransaction object is doorgevoerd of teruggedraaid, kan het niet meer worden gebruikt in een transactie. Dat wil gezegd, het kan niet worden ingesteld als de huidige context van de omgevingstransactie.

Een CommittableTransaction maken

In het volgende voorbeeld wordt een nieuwe CommittableTransaction gemaakt en doorgevoerd.

//Create a committable transaction
tx = new CommittableTransaction();

SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind");
SqlCommand myCommand = new SqlCommand();

//Open the SQL connection
myConnection.Open();

//Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx);

myCommand.Connection = myConnection;

// Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
myCommand.ExecuteNonQuery();

// Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
myCommand.ExecuteNonQuery();

// Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
myCommand.ExecuteNonQuery();

// Commit or rollback the transaction
while (true)
{
    Console.Write("Commit or Rollback? [C|R] ");
    ConsoleKeyInfo c = Console.ReadKey();
    Console.WriteLine();

    if ((c.KeyChar == 'C') || (c.KeyChar == 'c'))
    {
        tx.Commit();
        break;
    }
    else if ((c.KeyChar == 'R') || (c.KeyChar == 'r'))
    {
        tx.Rollback();
        break;
    }
}
myConnection.Close();
tx = null;
tx = New CommittableTransaction

Dim myConnection As New SqlConnection("server=(local)\SQLExpress;Integrated Security=SSPI;database=northwind")
Dim myCommand As New SqlCommand()

'Open the SQL connection
myConnection.Open()

'Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx)

myCommand.Connection = myConnection

'Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"
myCommand.ExecuteNonQuery()

'Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"
myCommand.ExecuteNonQuery()

'Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"
myCommand.ExecuteNonQuery()

'Commit or rollback the transaction
Dim c As ConsoleKeyInfo
While (True)
    Console.Write("Commit or Rollback? [C|R] ")
    c = Console.ReadKey()
    Console.WriteLine()

    If (c.KeyChar = "C") Or (c.KeyChar = "c") Then
        tx.Commit()
        Exit While
    ElseIf ((c.KeyChar = "R") Or (c.KeyChar = "r")) Then
        tx.Rollback()
        Exit While
    End If
End While

myConnection.Close()
tx = Nothing

Als u een exemplaar maakt, wordt de context van CommittableTransaction de omgevingstransactie niet automatisch ingesteld. Daarom maakt een bewerking voor een resourcemanager geen deel uit van die transactie. De statische Current eigenschap van het globale Transaction object wordt gebruikt om de omgevingstransactie in te stellen of op te halen en de toepassing moet deze handmatig instellen om ervoor te zorgen dat resourcemanagers aan de transactie kunnen deelnemen. Het is ook een goede gewoonte om de oude omgevingstransactie op te slaan en te herstellen wanneer u klaar bent met het gebruik van het CommittableTransaction object.

Als u de transactie wilt doorvoeren, moet u de Commit methode expliciet aanroepen. Als u een transactie wilt terugdraaien, moet u de Rollback methode aanroepen. Het is belangrijk te weten dat totdat een CommittableTransaction transactie is doorgevoerd of teruggedraaid, alle resources die betrokken zijn bij die transactie nog steeds zijn vergrendeld.

Een CommittableTransaction object kan worden gebruikt voor functieoproepen en threads. Het is echter aan de ontwikkelaar van de toepassing om uitzonderingen af te handelen en de Rollback(Exception) methode specifiek aan te roepen in geval van fouten.

Asynchrone doorvoer

De CommittableTransaction klasse biedt ook een mechanisme voor het asynchroon doorvoeren van een transactie. Een transactiedoorvoering kan veel tijd in beslag nemen, omdat het mogelijk meerdere databasetoegang en mogelijke netwerklatentie omvat. Als u impasses in toepassingen met hoge doorvoer wilt voorkomen, kunt u asynchrone doorvoer gebruiken om het transactionele werk zo snel mogelijk te voltooien en de doorvoerbewerking als achtergrondtaak uit te voeren. Met de BeginCommit en EndCommit methoden van de CommittableTransaction klasse kunt u dit doen.

U kunt aanroepen BeginCommit om de doorvoeropruiming naar een thread vanuit de threadgroep te verzenden. U kunt ook aanroepen EndCommit om te bepalen of de transactie daadwerkelijk is doorgevoerd. Als de transactie om welke reden dan ook niet kan worden doorgevoerd, EndCommit wordt een transactie-uitzondering gegenereerd. Als de transactie nog niet door de tijd EndCommit wordt vastgelegd, wordt de beller geblokkeerd totdat de transactie is doorgevoerd of afgebroken.

De eenvoudigste manier om een asynchrone doorvoering uit te voeren, is door een callback-methode op te geven die moet worden aangeroepen wanneer doorvoeren is voltooid. U moet echter de EndCommit methode aanroepen voor het oorspronkelijke CommittableTransaction object dat wordt gebruikt om de aanroep aan te roepen. Als u dat object wilt verkrijgen, kunt u de parameter IAsyncResult van de callback-methode downcastenIAsyncResult, omdat de CommittableTransaction klasse klasse implementeert.

In het volgende voorbeeld ziet u hoe een asynchrone doorvoering kan worden uitgevoerd.

public void DoTransactionalWork()  
{  
     Transaction oldAmbient = Transaction.Current;  
     CommittableTransaction committableTransaction = new CommittableTransaction();  
     Transaction.Current = committableTransaction;  
  
     try  
     {  
          /* Perform transactional work here */  
          // No errors - commit transaction asynchronously  
          committableTransaction.BeginCommit(OnCommitted,null);  
     }  
     finally  
     {  
          //Restore the ambient transaction
          Transaction.Current = oldAmbient;  
     }  
}  
void OnCommitted(IAsyncResult asyncResult)  
{  
     CommittableTransaction committableTransaction;  
     committableTransaction = asyncResult as CommittableTransaction;
     Debug.Assert(committableTransaction != null);  
     try  
     {  
          using(committableTransaction)  
          {  
               committableTransaction.EndCommit(asyncResult);  
          }  
     }  
     catch(TransactionException e)  
     {  
          //Handle the failure to commit  
     }  
}  

Zie ook