How to get PSPE-like behavior from a non-PSPE database

One of the new features in System.Transactions is the ability for the transaction manager to delegate directly to a resource manager (known as PSPE for Promotable Single Phase Enlistment). Currently, this is only supported by SQL 2005. That, then, raises the question about SQL 2000 -- does it promote directly to MSDTC, and is there anything that can be done about it?

 

It is the case that SQL 2000 will cause a promotion to MSDTC. This is because the SQL 2000 ADO.Net support does not provide a IPromotableSinglePhaseEnlistment instance, and the SQL 2000 resource manager is located in the SQL server process. Distribution to a second process is one of the actions that causes promotion.

 

However, for topologies that only involve a single database connection, there is a fairly simple mechanism that can be built that provides a PSPE-like shim for databases such as SQL 2000. This sort of shim would provide a PSPE interface to System.Transactions, and directly manage a SQL-local transaction behind the scenes. Its main limitation would be that it would for a rollback if the transaction ever needed to be promoted to MSDTC.

 

As an example, John Doty from our team has built such a set of classes. These are available for download at http://download.microsoft.com/download/B/D/0/BD0D4D33-89DC-497E-B3F2-95871A03A5F7/PrivateTransactionAdapter.msi. They are pretty heavily commented and provide both a SQL shim and a messaging shim (for use with a transactional queue resource, such as MSMQ).  Note that for SQL 2000, you need to make sure that your connection string has the phrase to prevent global auto-enlistment.

 

To use this, you simply:

 

    using (TransactionScope scope = new TransactionScope ())

    {

        ...

        SqlConnection conn = ...

        DatabaseTransactionAdapter adap = new DatabaseTransactionAdapter (conn);

        adap.Begin ();  // This creates the PSPE enlistment and the underlying

                        // private database transaction

        ...

        scope.Complete ();

    }

 

 

Take a look at these classes, and let me know what you think.

 

 

UPDATE: The msi file above (http://download.microsoft.com/download/B/D/0/BD0D4D33-89DC-497E-B3F2-95871A03A5F7/PrivateTransactionAdapter.msi) has been updated with a couple of bugfixes.


Posted Sep 13 2005, 07:58 AM by jim-johnson
Filed under:

Comments

Scott Galloway's Personal Blog wrote Some really nice posts on System.Transactions
on 09-16-2005 5:17 AM
I've posted about this namespace in the past, and its no secret I think this is a great feature in .NET...
Tomas Carlsson wrote re: How to get PSPE-like behavior from a non-PSPE database
on 12-14-2005 11:56 PM
Hello,
Thank you fore a good (and short) artickle.
I would like to make a distributed transaction over two databases (and be able to role back if anything goes wrong).

Is this possible with SQL Server 2000 and this pattern? I don't like to "mess up" my code with EnterproceServices and COM+.

I have tried to modify your code-example with two connections but I get an exeption that says "Cannot enlist in a distributed transaction", se my code below. What am I doing wrong?

Thank you for helping me ;)

Tomas


string connStrAar1Reg1 = GemFunktioner.AnslutningAarRegion(AAR_1);
connStrAar1Reg1 += "Enlist=false";
m_connAar1 = new SqlConnection(connStrAar1Reg1);
m_dbAdapterAar1 = new DatabaseTransactionAdapter(m_connAar1);
m_connAar1.Open();

string connStrAar2Reg1 = GemFunktioner.AnslutningAarRegion(AAR_2);
connStrAar2Reg1 += "Enlist=false";
m_connAar2 = new SqlConnection(connStrAar2Reg1);
m_dbAdapterAar2 = new DatabaseTransactionAdapter(m_connAar2);
m_connAar2.Open();

m_dbAdapterAar1.Begin();
m_dbAdapterAar2.Begin(); // Here I get the exeption "Cannot enlist in a distributed transaction"
jimjohn@microsoft.com wrote re: How to get PSPE-like behavior from a non-PSPE database
on 12-24-2005 2:40 PM
Tomas,

There are a few different questions and issues here.

First, I'd like to understand what your goals are here. I can assume that you don't want to build a full COM+ or ES component. Is that your issue, or is it using MSDTC as the coordinator? What is the physical topology involved?

My reason for asking is because, in the general case, a transaction that spans two SQL databases will end up coordinated by MSDTC (AFAIK). You might be able to hide the actual MSDTC mechanism using linked tables and a single SQL connection, but you will still be doing a distributed MSDTC transaction in the end.

Second, the DatabaseTransactionAdapter is limited to supporting transactions that do not promote out of PSPE. To handle the full promotion range, you really need SQL 2005. In your example, the call to Begin on the second adapter means that there are two resources, and the transaction needs to promote to MSDTC. That isn't supported, and hence the error.

To get the transaction in your code sample to work, but not require a COM+ or ES component, the simplest way is to just use SqlConnection, etc calls inside a TransactionScope, and to not bother with the DatabaseTransactionAdapter calls at all.

hth,
Jim.
Ahmet Kaymaz wrote re: How to get PSPE-like behavior from a non-PSPE database
on 01-07-2008 3:30 AM
C# VB.NET SQL Server örnek ve kodlari
Ahmet Kaymaz
http://www.ahmetkaymaz.com

Add a Comment

(required)  
(optional)
(required)  
Remember Me?