EDIT: I am only accessing 1 database but a DTC transaction IS being created. I can see it in the DTC Transaction List GUI (Component services plugin). Why is this?
I need to perform a transaction (several insert commands) against 1 database.
Should I be using TransactionScope or IDbTransaction (connection.BeginTransaction)?
TransactionScope seems to be newer … but should it just be used for 2-phase commits?
Thanks
TransactionScope will only escalate to a distributed transaction if it detects more than one connection. This means that TransactionScope is just as lightweight as BeginTransaction for local transactions and TransactionScope is a lot easier to use.
As long as you use a single connection and do not close and re-open during a TransactionScope, it should not promote to a distributed transaction. If you do not have the DTC service running on your machine it will throw an exception if it tries to promote. If the DTC running, you will be non the wiser of the promotion except for a slight pause.
In the vast majority of cases, TransactionScope is much nicer to use, especially in conjunction with "using" blocks.
Be careful though, if you use SQL Server 2000. It does not play well with TransactionScope and will always escalate to a distributed transaction.
See this link for some details.
Related
I have a small web api server written in C# using async/await. The Net version is 4.5.2
Everything is working fine except that I use TransactionScope for some calls and the underlying transaction is escalated to a distributed one. Since I use async/await for my db calls I use TransactionScopeAsyncFlowOption. The SQL server is running version 2008 r2 so it should be able to handle multiple calls without escelating the transaction. All calls are made to the same database with the same connection string.
All SQL connections are done in using statements and I'm not nesting any of them. Each call to the database is awaited before another is done so there should never be two connections active a the same time in one transaction, unless I have misunderstood how async/await works. I'm using Dapper if that might impact things.
Am I missing something obvious or do I need to rewrite my code to use the same connection for all operation in the transaction?
Feel really stupid, missed that Pooling was disabled in the connection string. Removed Pooling=false and the transaction does not escalate to a distributed state.
Is there anyway to find if a DbContext is enlisted in any transaction while enlist=false in the connection string?
I was tracing DbContext.Database.CurrentTransaction, but I noticed it is always null.
I know when enlist=false, all opened connections will not enlist themselves in an ambient transaction, is that right?
If (2) is correct, how to enlist DbContext in an transaction where TransactionScope is used?
Finally, I noticed using clones of DependentTransaction with multiple DbContext and multiple threads while enlist=false will not promote the transaction to distributed one, but I wonder am I still able to commit and rollback in case an exception happened using the dependent transaction while enlist=false?
if (4) is incorrect, then is there any way to fully avoid DistributedTransaction while being able to open multiple connections with a single transaction scope?
FYI, currently Oracle database is employed; however, in future MySQL is going to be in operation as well.
Thank you
I cant really say something to 1 , 2 and 3.. But:
The distribution-thing is not absolutely clear to me. But however, MS escalates Transactions from LTM (Lightweigt Transaction Manger) to DTC if a some criteria come to play. For Example if you try to access different databases in one transaction..
The escalation from LTM to DTC or the decission if an escalation will be forced is a system-decission. Until now I didnt find a way to change this behaviour. Thats why you need to think about the transactions in general. If there is a possibility to avoid multiple-database access you may rethink your transactions.
For further information I´ll recommend Why is my TransactionScope trying to use MSDTC when used in an EF Code First app? , MSSQL Error 'The underlying provider failed on Open' and How do I use TransactionScope in C#?
I am stuck using two db connections with entity framework contexts under a single transaction.
I am trying to use two db contexts under one transaction scope. I get "MSTDC not available". I read it's not an EF problem it's TDC which does not allow two connections.
Is there any answer for this problem?
This happens because the framework thinks that you are trying to have a transaction span multiple databases. This is called a distributed transaction.
To use distributed transactions, you need a transaction coordinator. In your case, the coordinator is the Microsoft Distributed Transaction Coordinator, which runs as a Widows Service on your server. You will need to make sure that this service is running:
Starting the service should solve your immediate issue.
Two-phase commit
From a purely theoretical point of view, distributed transactions are an impossibility* - that is, disparate systems cannot coordinate their actions in such a way that they can be absolutely certain that they either all commit or all roll back.
However, using a transaction coordinator, you get pretty darn close (and 'close enough' for any conceivable purpose). When using a distributed transaction, each party in the transaction will try to make the required changes and report back to the coordinator whether all went well or not. If all parties report success, the coordinator will tell all parties to commit. However, if one or more parties report a failure, the coordinator will tell all parties to roll back their changes. This is the "Two-phase commit protocol".
Watch out
It obviously takes time for the coordinator to communicate with the different parties of the transaction. Thus, using distributed transactions can hamper performance. Moreover, you may experience blocking and deadlocking among your transactions, and MSDTC obviously complicates your infrastructure.
Thus, before you turn on the Distributed Transaction Coordinator service and forge ahead with your project, you should first take a long, hard look at your architecture and convince yourself that you really need to use multiple contexts.
If you do need multiple contexts, you should investigate whether you can prevent transactions from being escalated to distributed transactions.
Further reading
You may want to read:
MSDN: "Managing Connections and Transactions" (specifically on EF)
Blog: "Avoid unwanted escalation to distributed transactions" (a bit dated, though)
***** See for example: Reasoning About Knowledge
You should run MSDTC (Distributed Transaction Coordinator) system service.
For LINQ i am using TransactionScope to handle transactions. When i execute the queries i get an exception.
Underlying connection failed to Open.
and the inner exception is saying something about DTC. I read online that i will have to enable some service on the server. But i donot want to do that. How can i use transcactions without enabling DTC. My code is something like this
public void function1()
{
using(TransactionScope t = new TransactionScope())
{
RunSomeSelectQueries();
RunSomeInsertQueries();
RunSomeUpdate Queries();
t.Complete();
}
}
Thanks in advance.
You have a serious problem in you tx handling that will push al ot of load into various levels.
TransactioNScope is nice, but
Calling methods that open separate connections WITHOUT NEED is bad.
Here is why:
If a Tx has one connection, it is handled in the kernel as local transaciton scope.
If you have multiple connections (transacted ressources) you need DTC.
And:
DTC is much slower than just a connection, with a lot more load on the server (multiple open connections - they have to stay open until the transaction commits). Also that turns into a multi step commit - generally a lot of overhead and making things slower.
That generally is a "hey, I just use transactions" antipattern.
Properly you should make sure you only create one database connection UNLESS YOU NEED MORE THAN ONE (like multiple databases are involved) so that the transaction scope does not proppagate to the DTC for having multiple ressources.
Obviously you also should configure DTC correctly IF you need it, but again: in this case the real problem is that you abuse the transaction scope forcing a DTC propagation where none is actually needed.
I get the following sql exception :
Transaction was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.
I don't have any transactions in any stored procedures, I do the transcation from .net and I always call them with using .
Have you guys met this before?
A transaction is a transaction, no matter where started. Whether in c# or the RDBMS.
Your using issues BEGIN TRANSCATION effectively.
MSDN (for SQL Server 2000 but still valid) recommends you retry automatically when a deadlock is detected, Rather than write code here, there are many results on Google for you to peruse.
When using the transaction you need to be careful as by default it sets the isolation level to serialisable. When the connection is released back into the pool it will still have that level set. This can seriously harm concurrency.