Very rarely have I met someone who intentionally wrote a program that would fail. Also very rarely have I met someone who doesn't tend to get frustrated when their program doesn't behave as they had anticipated it to do.
Most modern databases include fantastic support for transactions. Now ADO.NET is albeit the most important piece of your application architecture, but it is not the only piece that fits in your puzzle. Using database transactions you can keep your data sane, but what about the rest of the many operations your system needs to perform? Well, for those you use System.Transactions, and of course System.Transactions can, and probably will be used to databases as well.
What is System.Transactions?
System.Transactions is a new namespace introduced in .NET 2.0. The sole purpose of this namespace is to help you create Resource Managers that enlist in transactions, and provide you with a general infrastructure that lets you write more reliable transactional code. Could you do that before? Umm .. kinda !!! Because not everything was transactional, and AFAIK, atleast in .NET 2.0 Beta2, only SqlConnection works with System.Transactions. (It probably would be more appropriate to say that it enlists with a DTC using all the funky features of Sys.Tx, older transactional RMs such as MSMQ etc. continue to work with Sys.Tx, due to their existing transactional ability). But before you write this namespace off, consider two important points.
a) You can write your own RMs to leverage System.Transactions.
b) By god, be very sure of this that future stuff coming from Microsoft will make use of this technology very very heavily. So like it or not, you'd better get used to the concepts of "Transactional Programming under .NET".
So what is an RM? Oh wait, what is a DTC?
What is an RM or DTC?
Now in a distributed transaction, you could have units that perform the actual work and report a success or a failure. These units can be referred to as resource managers (RM). They are RMs because they “manage” a “resource” transactionally. And they are able to manage a resource transactionally because they contain enough hooks in them to work with an external entity – the DTC. So, in addition to the RM, you need some application who listens to and co-ordinates between RMs, which is typically referred to as the Distributed Transaction Coordinator (DTC).
The transaction coordinator that ships with windows is the MSDTC—Microsoft Distributed Transaction Coordinator. MSDTC is a windows service that provides transactional infrastructure for distributed applications. There is yet another transaction manager that is new with .NET 2.0 - the LTM (Light weight transaction manager), more on that shortly.
Here is a typical flow of a distributed transaction.
1. An application begins a transaction requesting one from the MSDTC. This application is commonly also referred to as the initiator.
2. The application then asks the resource manager to do its work as a part of the same transaction (this is actually configurable), and the resource managers register with the transaction manager as a part of the same transaction. This is commonly referred to as enlisting in a transaction.
3. If all goes well, the application commits the transaction.
4. If something fails, either step can issue a rollback.
5. In either case, the transaction coordinator coordinates with all the RMs to ensure that they all either succeed and do the requested work, or they all rollback their work.
MSDTC is used by MTS/COM+, System.EnterpriseServices, and starting .NET 2.0 in the new System.Transactions namespace. You can as a matter of fact, bypass both COM and .NET and simply use the MSDTC proxy msdtcprx.dll.
So in the 2nd para above, I mentioned LTM - now what the heck is LTM? And why should you care? Well, before I go into that - let me point out why MSDTC sucks .. but before I do that .. let me explain what Two Phase Commits are
What are two phase commits?
In a distributed transaction scenario, various resource managers implement what is commonly known as a two phase commit.
In a two phase commit, the actual commit for the work is split into two phases. The first phase involves preparing the changes required for the commit. At this point, the resource manager communicates to the transaction coordinator that it has its changes prepared and ready to be committed but not actually committed yet.
Once all the resource managers give the green flag to the transaction coordinator, the transaction coordinator then lets everyone know that it is okay to go ahead and commit their changes.
This picture is obviously over simplified, and entire books have been written on transaction coordinators and resource managers, but more on that later !! (Y'know you could read all this in my upcoming book too).
This brings up an interesting question. Who can participate in a distributed transaction? It is not just the database, or a number of databases that can participate in a distributed transaction. In fact, anything that has the ability to enlist itself in an MSDTC transaction can enlist itself in an MSDTC transaction. For instance, MSMQ can enlist in a transaction that has two other SqlConnection objects that connect to two different databases.
Anyway, before I digress too much, let me get back on topic and explain why MSDTC sucks.
Why does MSDTC suck?
I lied, it doesn't suck. Heehee :-)
Well, it doesn't suck because there is hardly any replacement for it, and for all you Linux hippie left wing leather panty crowd who is going to attack me for this statement, with names such as COMTI, those suck too for the same reasons MSDTC sucks.
Anyway, so why does MSDTC suck?
It bumps up isolation levels (or the RMs do to be safe, because you are writing transactional code for situations you cannot predict – you’d better be as safe as you can be)
It causes a lot of network traffic – two phase commit is very chatty.
It can run into network issues, or firewall issues.
It is a pig as far as hardcore performance goes.
But it is kinda unfair that every single transaction should pay the penalty of MSDTC .. right? Damn right it is unfair - luckily there is help.
What is the help? It's the LTM -
What is the LTM?
LTM is the Lightweight Transaction Manager. Well in short it is the coolest invention since the wheel. Okay maybe fire was the coolest invention .. or maybe that was the hottest. Anyway, so for transactions that don't need the full hoopla MSDTC provides, it is kinda unfair that those transactions should pay the price of a full fledged transaction. So LTM is the transaction manager that takes care of your transaction - provided your RM meets certain criteria. If in case the RM no longer meets that criteria, the transaction will then automatically be handed over to MSDTC.
The super ultra duper cool thing is, this escalation to MSDTC occurs behind the scenes - when you are using the RM - you are blissfully ignore of what is going on. As a matter of fact, thanks to the fantastic DataWorks team, SqlConnection supports this concept - this concept is called PROMOTABLE ENLISTMENT. (ooh the name sounds heavy duty doesn't it?)
So what is the criteria for an RM to work under LTM? It is almost easier to say what will get moved from LTM to MSDTC. So the escalation to MSDTC will happen if -
a) A durable RM shows up that doesn't support single phase notifications (another big name - hopefully I'll blog about it one day in the near future).
b) Two durable RMs show up in the same transaction.
c) The transaction spreads over multiple appdomains.
Again, the hella cool thing is - say when you are using SqlConnection, this escalation will happen behind the scenes, and you will remain blissfully ignorant. And say if you were writing an RM where performance was hella important - then you've gotta know how to create a promotable single phase enlistment - otherwise don't worry.