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.
Related
Say I'm having a Windows Form application which connected to n databases, with n connections opened simultaneously.
What I'm looking for is to do a transaction with all of those databases in one go.
For example if I were to have 2 database connections :
using (ITransaction tx1 = session1.OpenTransaction())
{
using (ITransaction tx2 = session2.OpenTransaction())
{
// Do the query thingy here
}
}
Writing all that is fine at first, but things get kind of redundant when I wanted to query here and there, and not to mention the possibility to adding a new connection.
What I wanted is to loop all of the registered session and wrap it up in a service, probably something like this :
class TransactionManager
{
private ISession[] _sessions;
public TransactionManager(string[] connectionStrings)
{
// Initialize the sessions here
}
public function DoTransaction(string query)
{
foreach (ISession session in _sessions)
{
// What to do here? Using? Try-catch?
}
}
}
If I were to use using in the foreach loop, it would mean that if connection A successful but connection B wasn't, then only connection B would be rolled back.
It seems you may be re-inventing TransactionScope. Doing all this under a unit of work is straightforward*:
using (TransactionScope scope = new TransactionScope())
{
... Do Stuff with Connection 1 using SqlDataReader
... Do Stuff with Connection 2 using Entity Framework
... Do Stuff with Connection 3 on another Oracle Database
... And for good measure do some stuff in MSMQ or other DTC resource
scope.Complete(); // If you are happy
}
Stuff doesn't need to be inline at all - it can be in a different class, or a different assembly. There's no need to explicitly register database or queue connections with the TransactionScope - everything happens automagically, provided that the resources you use are able to enlist into an ambient transaction.
Now the small print:
* Any time you use more than one database connection concurrently, or different connection strings, or multiple technologies, this will require 2 phase commit and escalate to a Distributed transaction in order to ensure ACID across the resources. MSDTC itself has lots more small print and poses many more challenges in a corporate network, like firewalls, clustering, security configuration and bugs.
However, with Lightweight transactions on MS Sql Server, if you can keep all your connections using the same database and same
connection string settings, and close each connection before opening
the next, then you can avoid
DTC.
Distributed Transactions are complex - you will need to install and configure the MSDTC service on your app server, and all distributed resources will need to have MSDTC or equivalent (e.g. XA, LUA) configured.
MSDTC isn't yet fully supported on .Net Core
Maintaining a transaction across multiple ACID resources will invariably maintain locks on these resources, until the transaction is committed or rolled back. This often doesn't make for good neighbourliness in a high volume enterprise, so be sure to consider the consequences of the locking.
If the Stuff is done across multiple threads, you'll need to rope in DependentTransaction
A last point worth mentioning is the default isolation level with TransactionScope is Serializable, which is prone to deadlocks. In most non-critical scenarios you'll probably be able drop this down to Read Committed.
use TransactionScope, it will take care of committing or rolling back all included transactions:
using (var ts = new TransactionScope())
{
... // your old code
ts.Complete()
}
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#?
How can I use TransactionScope? I can hardly find any info about that. My project wont recognize TransactionScope and turns red when I try to call it. I tried with using System.Transactions.TransactionScope; but it didn't work either.
Also once its get worked, will Method_A(); to Method_C(); being within transaction then? Meaning if anything would fail e.g. in Method_C();, would everything rollback including Method_A();and Method_B();? That's the behavior I want.
private void method_A(){/* doing tons of db stuff */}
private void method_B(){/*...*/}
private void method_C(){/*...*/}
protected void Insert_OnClick(object sender, EventArgs e)
{
using(TransactionScope tran = new TransactionScope())
{
Method_A();
Method_B();
Method_C();
tran.Complete();
}
}
Using C#, ASP.NET and ms Access.
TransactionScope is not available for Microsoft Access, so you cannot use it.
Have a look at this question for alternative implementations of Transaction Scope.
As for the transactional scope, see this link
Relevant Quote:
Within one Workspace object, transactions are always global to the Workspace and aren't limited to only one Connection or Database object. If you perform operations on more than one connection or database within a Workspace transaction, resolving the transaction (that is, using the CommitTrans or Rollback method) affects all operations on all connections and databases within that workspace.
This means that everything you do on the Access-File within your workspace is within the transaction, even if you access the workspace from somewhere else while the transaction is still going.
Keep this in mind:
The behavior of transactions with Access databases differs from the behavior of ODBC data sources, such as Microsoft SQL Server. For example, if a database is connected to a file server, and the file server stops before a transaction has had time to commit its changes, then your database could be left in an inconsistent state. If you require true transaction support with respect to durability, you should investigate using a client/server architecture.
I'm using EF6.1 and SQL Server on a WPF thick-client application and by default I'm opening a transaction with each DbContext I instantiate (I commit it and reopen it on every SaveChanges() unless specified otherwise). The isolation level for these transactions is READ COMMITED (IsolationLevel.ReadCommited).
I'm by default opening a new context (thus a new transaction) on each "main view". The application is kind of a fake-MDI app and each MDI View will use its own DbContext... "main views" (every MDI tab/window) can contain other secondary views (think of small modal windows for specific data entry and things like that) which will share the same context (and transaction) as the opened in the main view. I'm using a structure like UseCase -> Views -> ViewModels... generally a "UseCase" will open up a DbContext and can spawn multiple views, which will share it. Those secondary views usually call SaveChanges() without committing the transaction, that's why I want to have them in first place.
I've done some performance tests with a single user on a lab server and there doesn't seem to exist any difference (performance-wise) either opening the transaction when instancing the context, or not having transactions at all (other than the one EF opens by default on SaveChanges()).
I'm no SQL Server expert, so I'm wondering if there are any implications (when the app is used by multiple users on a production server) on having many long-running transactions opened on SQL Server with that isolation level (I understand the implications on other isolation levels which may lock reads, but it's not the case). I'm handling concurrency errors manually when committing the transactions.
Am I doing the right thing here, should I stick to short-living transactions, or is it just a matter of preference?
I've been trying to find an answer to this but haven't found anything definitive (there's some people that says long-living transactions are not a good idea, but they don't seem to explain why).
there's some people that says long-living transactions are not a good
idea, but they don't seem to explain why
Just a couple of reasons:
MS SQL transaction, depending on its isolation level, could obtain record (more general) or even metadata (more exotic) locks. The more time transaction lives, the more locks it could obtain, hence, the probability of deadlocks increases.
Also, uncommitted transaction means server resource utilization. Transaction log will grow and its data for active transactions could not be truncated, server must remember all of things, which has been done within transaction to commit them or rollback.
by default I'm opening a transaction with each DbContext I instantiate
There should be a reason to do this. The only reason I can imagine, is non-EF changes to a database, which must be consistent with EF changes. Otherwise, you're doing an extra-job, which at least useless, and could waste resources of database server.
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.