Flylib.com

Books Software

 
 
 

17.14 Use a COM Distributed Transaction


17.14 Use a COM+ Distributed Transaction

Problem

You want to perform multiple operations with different data sources, and you want these operations to either fail or succeed as a unit.

Solution

Derive your class from ServicedComponent , specify the type of transactional behavior you want by adding the Transaction attribute to the class declaration, and add the AutoComplete attribute to all methods .

Discussion

COM+ allows you to create classes that have set transaction requirements. When a client uses a method in a transactional class, a transaction will be started automatically, and committed when the code completes. Coding transactions in this way is easy and transparent. It also allows you to flexibly tie multiple methods together in a single transaction at runtime. However, COM+ transactions require the Distributed Transaction Coordinator (DTC) service on the computer to coordinate all transactions using a two-stage commit process. This is inherently slower than a simple database-initiated transaction. For that reason, COM+ transactions are most often used when you need to create a transaction that spans multiple data sources (such as an Oracle database and a SQL Server database).

To use distributed transactions, you must first create a serviced component, as described in recipe 17.11. Then, add the System.EnterpriseServices.Transaction attribute to the class that will run inside the transaction and specify a value from the TransactionOption enumeration. Supported values include

  • Required     This object must run in a transaction. If the caller has already started a transaction, this object participates inside that transaction. Otherwise, a new transaction is created.

  • RequiresNew    This object must run in a transaction. If the caller has already started a transaction, a new and completely independent transaction is created for this object.

  • Supported    This object can run in a transaction and is enlisted in the caller's transaction if it exists. Otherwise, this object doesn't run in a transaction.

  • NotSupported    This object doesn't participate in a transaction. If the caller has a current transaction, this object can't vote on it.

  • Disabled     The object doesn't have any transaction requirements. This is the default value. In .NET, this value is equivalent to NotSupported .

In a COM+ transaction, every participating object must vote to commit or abort the transaction. If any object votes to abort, the entire transaction is rolled back. Your object can vote by setting the shared ContextUtil.MyTransactionVote property. However, a simpler approach is to add the AutoComplete attribute to all methods. In this case, the transaction will be automatically committed if the code completes successfully and aborted if an unhandled exception is encountered .

The following class provides an AttemptChanges method that modifies a SQL Server database. However, before the method completes, an unhandled exception is thrown, and the entire transaction is rolled back.

<Transaction(TransactionOption.Required)> _ Public Class TransactionTest Inherits ServicedComponent Private ConnectionString As String = "Data Source=localhost;" & _ "Integrated Security=SSPI;Initial Catalog=Northwind" <AutoComplete()> _ Public Sub AttemptChanges() ' Delete records from SQL Server. Dim Con As New SqlConnection(ConnectionString) Dim Cmd As New SqlCommand("DELETE * FROM Customers", Con) Try Con.Open() Cmd.ExecuteNonQuery() Finally Con.Close() End Try ' (Access another data source here.) ' This unhandled exception will cause all transactional ' operations to be rolled back. ' You could also set the vote manually using ' ContextUtil.MyTransactionVote = TransactionVote.Abort ' ContextUtil.DeactivateOnReturn = True Throw New ApplicationException("Task aborted.") End Sub End Class

Note 

If a data source supports COM+ transactions, it will automatically be enlisted in the current transaction. However, some operations (such as writing a file to disk) are inherently not transactional. That means that these operations won't be rolled back if the transaction fails.