Roll Back Insert SQL Server [duplicate] - c#

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()
}

Related

Why is DbContext.Database.CurrentTransaction always null?

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#?

Cant get TransactionScope working

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.

MSSQL Timeout error

I'm using MSSQL Server 2008. I have to work with several databases at a time. Some tomes the system gives an error "Transaction Timeout" when the insert or update records. But it works after a few minute.
There are few users are using differences windows applications to manipulate data in databases.
I want to know,
is there any relation between this issue and multiple database usage ?
Is this query type (multiple database linked in a query) will effect to the Timeout ?
Highly depends on the timeout's reason. Frequently it is caused when resources are locked by one application and the second application waits too long. Multiple databases, even in single instance, are using Distibuted Transaction Coordinator.
A transaction within a single instance of the Database Engine that
spans two or more databases is actually a distributed transaction. The
instance manages the distributed transaction internally; to the user,
it operates as a local transaction.
http://technet.microsoft.com/en-us/library/jj856598(v=sql.110).aspx
And the DTC is much slower than working in the scope of the same database, so it causes data to be locked for a wider timeframe and might cause timeouts.
If you're using SqlConnection, SqlCommand and Transaction you may want to check and set each of these timeout property to manage properly your application behaviour.
See TransactionOptions for IsolationLevel and TimeOut (the first one maybe has to be Required)
See SqlCommand.CommandTimeout if you're using commands.
A good way to use transaction could be
TimeSpan timeout = TimeSpan.FromSeconds(300); // 5 minutes
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, timeout))
{
// Code ...
}
Keep in mind that a lot of concurrent transactions could affect SQL Server efficiency. Maybe you need different instances of the same Server to use it properly, but the cons come with synchronization of each instance.

Transaction Scope giving underlying connection failed to open

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.

Transaction Scope in details with so many transaction and its advantage

I am having more then 20 transaction in in one shot. I want to use transaction scope with this. Is it possible? And If possible then what is the advantage of using transacation scope class over simple transaction.
What is the best practice to use transaction scope?
The advantages of TransactionScope are:
you don't have to pass a transaction around (ADO.NET should enlist automatically)
which means that you can even use a TransactionScope to add transactions to existing, closed-source code (i.e. no changes are required)
a TransactionScope can (via DTC) span multiple resources (i.e. multiple databases, or a database and an MSMQ server, etc)
But you pay for this a little bit with speed. A connection-based transaction is slightly quicker (not much), but can only span a single resource and needs to be attached manually to all your DAL code. However, if you only talk to a single SQL2005/SQL2008 instance, then it can use the "LTM" - meaning it doesn't have to involve DTC (which is where most of the performance cost comes from) unless it absolutely needs to. Many TransactionScope operations can therefore complete talking only to the database.
If you want to span 20 operations, then TransactionScope should be ideal - it'll save you having to pass the transactions around, and allow each operation to manage their connection locally - making for highly re-usable code. Indeed, TransactionScope can be nested in the ways you expect, so you can have:
void Deposit(...) { /* uses TranScope to do a deposit */ }
void Debit(...) { /* uses TranScope to do a debit */ }
void Transfer(...) { /* uses a TranScope to span Debit/Deposit */ }
To do this using database transactions you'd need to pass the connection and transaction objects to each method, which quickly gets ungainly - especially if you need to code to work with/without an existing open transaction (lots of "if(tran==null)" etc).
For more information, see Transactions in .net

Categories